Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --add-plugin argument #1496

Open
wants to merge 3 commits into
base: dev/3.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions proxy/src/main/java/com/velocitypowered/proxy/ProxyOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public final class ProxyOptions {
private final @Nullable Boolean haproxy;
private final boolean ignoreConfigServers;
private final List<ServerInfo> servers;
private final List<String> additionalPlugins;

ProxyOptions(final String[] args) {
final OptionParser parser = new OptionParser();
Expand All @@ -64,13 +65,18 @@ public final class ProxyOptions {
final OptionSpec<Void> ignoreConfigServers = parser.accepts("ignore-config-servers",
"Skip registering servers from the config file. "
+ "Useful in dynamic setups or with the --add-server flag.");
final OptionSpec<String> additionalPlugins = parser.acceptsAll(Arrays.asList("add-plugin", "add-extra-plugin-jar"),
"Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. "
+ "This argument can be specified multiple times, once for each extra plugin jar path."
).withRequiredArg().ofType(String.class);
final OptionSet set = parser.parse(args);

this.help = set.has(help);
this.port = port.value(set);
this.haproxy = haproxy.value(set);
this.servers = servers.values(set);
this.ignoreConfigServers = set.has(ignoreConfigServers);
this.additionalPlugins = additionalPlugins.values(set);

if (this.help) {
try {
Expand Down Expand Up @@ -101,6 +107,10 @@ public List<ServerInfo> getServers() {
return this.servers;
}

public List<String> getAdditionalPlugins() {
return this.additionalPlugins;
}

private static class ServerInfoConverter implements ValueConverter<ServerInfo> {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ private void loadPlugins() {

try {
Path pluginPath = Path.of("plugins");
ArrayList<Path> additionalPlugins = new ArrayList<>();

if (!pluginPath.toFile().exists()) {
Files.createDirectory(pluginPath);
Expand All @@ -423,9 +424,24 @@ private void loadPlugins() {
pluginPath);
return;
}
}

pluginManager.loadPlugins(pluginPath);
for (String additionalPluginPath : options.getAdditionalPlugins()) {
Path path = Path.of(additionalPluginPath);
if (!Files.exists(path)) {
logger.warn("Unable to find plugin file by path {}",
additionalPluginPath);
continue;
}
if (!path.toFile().isFile()) {
logger.warn("Plugin {} is not a file",
additionalPluginPath);
continue;
}
additionalPlugins.add(path);
}

pluginManager.loadPlugins(pluginPath, additionalPlugins);
} catch (Exception e) {
logger.error("Couldn't load plugins", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,42 +79,60 @@ public void registerPlugin(PluginContainer plugin) {
instance.ifPresent(o -> pluginInstances.put(o, plugin));
}

private void loadPluginDescription(JavaPluginLoader loader, Map<String, PluginDescription> foundCandidates, Path path) {
try {
PluginDescription candidate = loader.loadCandidate(path);

// If we found a duplicate candidate (with the same ID), don't load it.
PluginDescription maybeExistingCandidate = foundCandidates.putIfAbsent(
candidate.getId(), candidate);

if (maybeExistingCandidate != null) {
logger.error("Refusing to load plugin at path {} since we already "
+ "loaded a plugin with the same ID {} from {}",
candidate.getSource().map(Objects::toString).orElse("<UNKNOWN>"),
candidate.getId(),
maybeExistingCandidate.getSource().map(Objects::toString).orElse("<UNKNOWN>"));
}
} catch (Throwable e) {
logger.error("Unable to load plugin {}", path, e);
}
}

private static boolean isJarFile(Path p) {
return p.toFile().isFile() && p.toString().endsWith(".jar");
}

/**
* Loads all plugins from the specified {@code directory}.
* Loads all plugins from the {@code directory} and by paths {@code extraPluginJars}.
*
* @param directory the directory to load from
* @param extraPluginJars the path to additional plugins jar's
* @throws IOException if we could not open the directory
*/
@SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE",
justification = "I looked carefully and there's no way SpotBugs is right.")
public void loadPlugins(Path directory) throws IOException {
checkNotNull(directory, "directory");
checkArgument(directory.toFile().isDirectory(), "provided path isn't a directory");
public void loadPlugins(Path directory, Collection<Path> extraPluginJars) throws IOException {

Map<String, PluginDescription> foundCandidates = new LinkedHashMap<>();
JavaPluginLoader loader = new JavaPluginLoader(server, directory);

try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory,
p -> p.toFile().isFile() && p.toString().endsWith(".jar"))) {
for (Path path : stream) {
try {
PluginDescription candidate = loader.loadCandidate(path);

// If we found a duplicate candidate (with the same ID), don't load it.
PluginDescription maybeExistingCandidate = foundCandidates.putIfAbsent(
candidate.getId(), candidate);
for (Path path : extraPluginJars) {
if (VelocityPluginManager.isJarFile(path)) {
loadPluginDescription(loader, foundCandidates, path);
}
}

if (maybeExistingCandidate != null) {
logger.error("Refusing to load plugin at path {} since we already "
+ "loaded a plugin with the same ID {} from {}",
candidate.getSource().map(Objects::toString).orElse("<UNKNOWN>"),
candidate.getId(),
maybeExistingCandidate.getSource().map(Objects::toString).orElse("<UNKNOWN>"));
}
} catch (Throwable e) {
logger.error("Unable to load plugin {}", path, e);
if (directory.toFile().isDirectory()) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory,
VelocityPluginManager::isJarFile)) {
for (Path path : stream) {
loadPluginDescription(loader, foundCandidates, path);
}
}
} else {
logger.warn("Plugin location {} is not a directory, continuing without loading plugins",
directory);
}

if (foundCandidates.isEmpty()) {
Expand Down