Added the ability to suppress arbitrary warnings and errors.

This commit is contained in:
Kristian S. Stangeland 2013-06-01 00:17:08 +02:00
parent 77346f8438
commit aa5e1beb7f
4 changed files with 205 additions and 75 deletions

View File

@ -19,6 +19,7 @@ package com.comphenix.protocol;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.bukkit.configuration.Configuration; import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
@ -26,6 +27,8 @@ import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.io.Files; import com.google.common.io.Files;
/** /**
@ -48,6 +51,7 @@ class ProtocolConfig {
private static final String INJECTION_METHOD = "injection method"; private static final String INJECTION_METHOD = "injection method";
private static final String SCRIPT_ENGINE_NAME = "script engine"; private static final String SCRIPT_ENGINE_NAME = "script engine";
private static final String SUPPRESSED_REPORTS = "suppressed reports";
private static final String UPDATER_NOTIFY = "notify"; private static final String UPDATER_NOTIFY = "notify";
private static final String UPDATER_DOWNLAD = "download"; private static final String UPDATER_DOWNLAD = "download";
@ -68,6 +72,9 @@ class ProtocolConfig {
private boolean configChanged; private boolean configChanged;
private boolean valuesChanged; private boolean valuesChanged;
// Modifications
private int modCount;
public ProtocolConfig(Plugin plugin) { public ProtocolConfig(Plugin plugin) {
this(plugin, plugin.getConfig()); this(plugin, plugin.getConfig());
} }
@ -84,6 +91,7 @@ class ProtocolConfig {
// Reset // Reset
configChanged = false; configChanged = false;
valuesChanged = false; valuesChanged = false;
modCount++;
this.config = plugin.getConfig(); this.config = plugin.getConfig();
this.lastUpdateTime = loadLastUpdate(); this.lastUpdateTime = loadLastUpdate();
@ -199,6 +207,7 @@ class ProtocolConfig {
*/ */
public void setAutoNotify(boolean value) { public void setAutoNotify(boolean value) {
setConfig(updater, UPDATER_NOTIFY, value); setConfig(updater, UPDATER_NOTIFY, value);
modCount++;
} }
/** /**
@ -215,6 +224,7 @@ class ProtocolConfig {
*/ */
public void setAutoDownload(boolean value) { public void setAutoDownload(boolean value) {
setConfig(updater, UPDATER_DOWNLAD, value); setConfig(updater, UPDATER_DOWNLAD, value);
modCount++;
} }
/** /**
@ -233,6 +243,24 @@ class ProtocolConfig {
*/ */
public void setDebug(boolean value) { public void setDebug(boolean value) {
setConfig(global, DEBUG_MODE_ENABLED, value); setConfig(global, DEBUG_MODE_ENABLED, value);
modCount++;
}
/**
* Retrieve an immutable list of every suppressed report type.
* @return Every suppressed report type.
*/
public ImmutableList<String> getSuppressedReports() {
return ImmutableList.copyOf(global.getStringList(SUPPRESSED_REPORTS));
}
/**
* Set the list of suppressed report types,
* @param reports - suppressed report types.
*/
public void setSuppressedReports(List<String> reports) {
global.set(SUPPRESSED_REPORTS, Lists.newArrayList(reports));
modCount++;
} }
/** /**
@ -255,6 +283,7 @@ class ProtocolConfig {
if (delaySeconds < DEFAULT_UPDATER_DELAY) if (delaySeconds < DEFAULT_UPDATER_DELAY)
delaySeconds = DEFAULT_UPDATER_DELAY; delaySeconds = DEFAULT_UPDATER_DELAY;
setConfig(updater, UPDATER_DELAY, delaySeconds); setConfig(updater, UPDATER_DELAY, delaySeconds);
modCount++;
} }
/** /**
@ -275,6 +304,7 @@ class ProtocolConfig {
*/ */
public void setIgnoreVersionCheck(String ignoreVersion) { public void setIgnoreVersionCheck(String ignoreVersion) {
setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion); setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion);
modCount++;
} }
/** /**
@ -294,6 +324,7 @@ class ProtocolConfig {
*/ */
public void setMetricsEnabled(boolean enabled) { public void setMetricsEnabled(boolean enabled) {
setConfig(global, METRICS_ENABLED, enabled); setConfig(global, METRICS_ENABLED, enabled);
modCount++;
} }
/** /**
@ -313,6 +344,7 @@ class ProtocolConfig {
*/ */
public void setBackgroundCompilerEnabled(boolean enabled) { public void setBackgroundCompilerEnabled(boolean enabled) {
setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled); setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled);
modCount++;
} }
/** /**
@ -325,6 +357,9 @@ class ProtocolConfig {
/** /**
* Set the last time we updated, in seconds since 1970.01.01 00:00. * Set the last time we updated, in seconds since 1970.01.01 00:00.
* <p>
* Note that this is not considered to modify the configuration, so the modification count
* will not be incremented.
* @param lastTimeSeconds - new last update time. * @param lastTimeSeconds - new last update time.
*/ */
public void setAutoLastTime(long lastTimeSeconds) { public void setAutoLastTime(long lastTimeSeconds) {
@ -348,6 +383,7 @@ class ProtocolConfig {
*/ */
public void setScriptEngineName(String name) { public void setScriptEngineName(String name) {
setConfig(global, SCRIPT_ENGINE_NAME, name); setConfig(global, SCRIPT_ENGINE_NAME, name);
modCount++;
} }
/** /**
@ -380,6 +416,15 @@ class ProtocolConfig {
*/ */
public void setInjectionMethod(PlayerInjectHooks hook) { public void setInjectionMethod(PlayerInjectHooks hook) {
setConfig(global, INJECTION_METHOD, hook.name()); setConfig(global, INJECTION_METHOD, hook.name());
modCount++;
}
/**
* Retrieve the number of modifications made to this configuration.
* @return The number of modifications.
*/
public int getModificationCount() {
return modCount;
} }
/** /**

View File

@ -19,6 +19,7 @@ package com.comphenix.protocol;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Set;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
@ -34,6 +35,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.async.AsyncFilterManager; import com.comphenix.protocol.async.AsyncFilterManager;
import com.comphenix.protocol.error.BasicErrorReporter; import com.comphenix.protocol.error.BasicErrorReporter;
import com.comphenix.protocol.error.DelegatedErrorReporter;
import com.comphenix.protocol.error.DetailedErrorReporter; import com.comphenix.protocol.error.DetailedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
@ -47,6 +49,9 @@ import com.comphenix.protocol.metrics.Updater.UpdateResult;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler; import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.utility.ChatExtensions; import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/** /**
* The main entry point for ProtocolLib. * The main entry point for ProtocolLib.
@ -136,12 +141,12 @@ public class ProtocolLibrary extends JavaPlugin {
// Add global parameters // Add global parameters
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this); DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
reporter = detailedReporter; reporter = getFilteredReporter(detailedReporter);
try { try {
config = new ProtocolConfig(this); config = new ProtocolConfig(this);
} catch (Exception e) { } catch (Exception e) {
detailedReporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e)); reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_LOAD_CONFIG).error(e));
// Load it again // Load it again
if (deleteConfig()) { if (deleteConfig()) {
@ -168,7 +173,7 @@ public class ProtocolLibrary extends JavaPlugin {
unhookTask = new DelayedSingleTask(this); unhookTask = new DelayedSingleTask(this);
protocolManager = new PacketFilterManager( protocolManager = new PacketFilterManager(
getClassLoader(), getServer(), this, version, unhookTask, detailedReporter); getClassLoader(), getServer(), this, version, unhookTask, reporter);
// Setup error reporter // Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager); detailedReporter.addGlobalParameter("manager", protocolManager);
@ -183,23 +188,52 @@ public class ProtocolLibrary extends JavaPlugin {
protocolManager.setPlayerHook(hook); protocolManager.setPlayerHook(hook);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
detailedReporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e)); reporter.reportWarning(config, Report.newBuilder(REPORT_CANNOT_PARSE_INJECTION_METHOD).error(e));
} }
// Initialize command handlers // Initialize command handlers
commandProtocol = new CommandProtocol(detailedReporter, this, updater, config); commandProtocol = new CommandProtocol(reporter, this, updater, config);
commandFilter = new CommandFilter(detailedReporter, this, config); commandFilter = new CommandFilter(reporter, this, config);
commandPacket = new CommandPacket(detailedReporter, this, logger, commandFilter, protocolManager); commandPacket = new CommandPacket(reporter, this, logger, commandFilter, protocolManager);
// Send logging information to player listeners too // Send logging information to player listeners too
setupBroadcastUsers(PERMISSION_INFO); setupBroadcastUsers(PERMISSION_INFO);
} catch (Throwable e) { } catch (Throwable e) {
detailedReporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager)); reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager));
disablePlugin(); disablePlugin();
} }
} }
/**
* Retrieve a error reporter that may be filtered by the configuration.
* @return The new default error reporter.
*/
private ErrorReporter getFilteredReporter(ErrorReporter reporter) {
return new DelegatedErrorReporter(reporter) {
private int lastModCount = -1;
private Set<String> reports = Sets.newHashSet();
@Override
protected Report filterReport(Object sender, Report report, boolean detailed) {
String canonicalName = ReportType.getReportName(sender.getClass(), report.getType());
String reportName = Iterables.getLast(Splitter.on("#").split(canonicalName)).toUpperCase();
if (config != null && config.getModificationCount() != lastModCount) {
// Update our cached set again
reports = Sets.newHashSet(config.getSuppressedReports());
lastModCount = config.getModificationCount();
}
// Cancel reports either on the full canonical name, or just the report name
if (reports.contains(canonicalName) || reports.contains(reportName))
return null;
else
return report;
}
};
}
private boolean deleteConfig() { private boolean deleteConfig() {
return config.getFile().delete(); return config.getFile().delete();
} }

View File

@ -1,66 +1,115 @@
package com.comphenix.protocol.error; package com.comphenix.protocol.error;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
/** import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
* Represents a strongly-typed report. Subclasses should be immutable.
* <p> /**
* By convention, a report must be declared as a static field publicly accessible from the sender class. * Represents a strongly-typed report. Subclasses should be immutable.
* @author Kristian * <p>
*/ * By convention, a report must be declared as a static field publicly accessible from the sender class.
public class ReportType { * @author Kristian
private final String errorFormat; */
public class ReportType {
/** private final String errorFormat;
* Construct a new report type.
* @param errorFormat - string used to format the underlying report. // Used to store the report name
*/ protected String reportName;
public ReportType(String errorFormat) {
this.errorFormat = errorFormat; /**
} * Construct a new report type.
* @param errorFormat - string used to format the underlying report.
/** */
* Convert the given report to a string, using the provided parameters. public ReportType(String errorFormat) {
* @param parameters - parameters to insert, or NULL to insert nothing. this.errorFormat = errorFormat;
* @return The full report in string format. }
*/
public String getMessage(Object[] parameters) { /**
if (parameters == null || parameters.length == 0) * Convert the given report to a string, using the provided parameters.
return toString(); * @param parameters - parameters to insert, or NULL to insert nothing.
else * @return The full report in string format.
return String.format(errorFormat, parameters); */
} public String getMessage(Object[] parameters) {
if (parameters == null || parameters.length == 0)
@Override return toString();
public String toString() { else
return errorFormat; return String.format(errorFormat, parameters);
} }
/** @Override
* Retrieve all publicly associated reports. public String toString() {
* @param clazz - sender class. return errorFormat;
* @return All associated reports. }
*/
public static ReportType[] getReports(Class<?> clazz) { /**
if (clazz == null) * Retrieve the full canonical name of a given report type.
throw new IllegalArgumentException("clazz cannot be NULL."); * <p>
List<ReportType> result = new ArrayList<ReportType>(); * This is in the format <i>canonical_name_of_class#report_type</i>
* @param clazz - the sender class.
for (Field field : clazz.getFields()) { * @param type - the report instance.
if (Modifier.isStatic(field.getModifiers()) && * @return The full canonical name.
ReportType.class.isAssignableFrom(field.getDeclaringClass())) { */
try { public static String getReportName(Class<?> sender, ReportType type) {
result.add((ReportType) field.get(null)); if (sender == null)
} catch (IllegalAccessException e) { throw new IllegalArgumentException("sender cannot be NUll.");
throw new FieldAccessException("Unable to access field.", e);
} // Whether or not we need to retrieve the report name again
} if (type.reportName == null) {
} for (Field field : getReportFields(sender)) {
return result.toArray(new ReportType[0]); try {
} field.setAccessible(true);
}
if (field.get(null) == type) {
// We got the right field!
return type.reportName = field.getDeclaringClass().getCanonicalName() + "#" + field.getName();
}
} catch (IllegalAccessException e) {
throw new FieldAccessException("Unable to read field " + field, e);
}
}
throw new IllegalArgumentException("Cannot find report name for " + type);
}
return type.reportName;
}
/**
* Retrieve all publicly associated reports.
* @param sender - sender class.
* @return All associated reports.
*/
public static ReportType[] getReports(Class<?> sender) {
if (sender == null)
throw new IllegalArgumentException("sender cannot be NULL.");
List<ReportType> result = new ArrayList<ReportType>();
// Go through all the fields
for (Field field : getReportFields(sender)) {
try {
field.setAccessible(true);
result.add((ReportType) field.get(null));
} catch (IllegalAccessException e) {
throw new FieldAccessException("Unable to read field " + field, e);
}
}
return result.toArray(new ReportType[0]);
}
/**
* Retrieve all publicly associated report fields.
* @param clazz - sender class.
* @return All associated report fields.
*/
private static List<Field> getReportFields(Class<?> clazz) {
return FuzzyReflection.fromClass(clazz).getFieldList(
FuzzyFieldContract.newBuilder().
requireModifier(Modifier.STATIC).
typeDerivedOf(ReportType.class).
build()
);
}
}

View File

@ -22,4 +22,6 @@ global:
debug: false debug: false
# The engine used by the filter command # The engine used by the filter command
script engine: JavaScript script engine: JavaScript
suppressed reports: