Skip to content

Commit

Permalink
Update helper-js for latest scriptcontroller changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lucko committed Mar 21, 2018
1 parent fdc696a commit 510b9bb
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 206 deletions.
18 changes: 17 additions & 1 deletion helper-js/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<description>JavaScript plugins using Nashorn.</description>
<url>https://github.com/lucko/helper</url>

<properties>
<shade.pattern>me.lucko.helper.js.external.</shade.pattern>
</properties>

<build>
<defaultGoal>clean package</defaultGoal>
<finalName>${project.name}</finalName>
Expand Down Expand Up @@ -68,6 +72,12 @@
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>io.github.lukehutch.fastclasspathscanner</pattern>
<shadedPattern>${shade.pattern}fcs</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
Expand Down Expand Up @@ -116,7 +126,13 @@
<dependency>
<groupId>me.lucko</groupId>
<artifactId>scriptcontroller</artifactId>
<version>1.0</version>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.github.lukehutch</groupId>
<artifactId>fast-classpath-scanner</artifactId>
<version>2.9.5</version>
<scope>compile</scope>
</dependency>

Expand Down
218 changes: 187 additions & 31 deletions helper-js/src/main/java/me/lucko/helper/js/HelperJsPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,113 @@

package me.lucko.helper.js;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;

import me.lucko.helper.Schedulers;
import me.lucko.helper.js.bindings.GeneralScriptBindings;
import me.lucko.helper.js.bindings.HelperScriptBindings;
import me.lucko.helper.internal.LoaderUtils;
import me.lucko.helper.menu.scheme.MenuScheme;
import me.lucko.helper.menu.scheme.SchemeMapping;
import me.lucko.helper.metadata.MetadataKey;
import me.lucko.helper.plugin.ExtendedJavaPlugin;
import me.lucko.helper.scheduler.Ticks;
import me.lucko.helper.terminable.composite.CompositeTerminable;
import me.lucko.helper.text.Text;
import me.lucko.scriptcontroller.ScriptController;
import me.lucko.scriptcontroller.bindings.BindingsBuilder;
import me.lucko.scriptcontroller.bindings.BindingsSupplier;
import me.lucko.scriptcontroller.environment.ScriptEnvironment;
import me.lucko.scriptcontroller.environment.loader.ScriptLoadingExecutor;
import me.lucko.scriptcontroller.environment.script.Script;
import me.lucko.scriptcontroller.environment.settings.EnvironmentSettings;
import me.lucko.scriptcontroller.logging.SystemLogger;

import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;

import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;

public class HelperJsPlugin extends ExtendedJavaPlugin {
/**
* Uses {@link ScriptController} and helper to provide a javascript plugin environment for Bukkit.
*/
public class HelperJsPlugin extends ExtendedJavaPlugin implements ScriptLoadingExecutor {

/**
* The packages to import by default when each script is executed.
* These strings are pattern specs for the FastClasspathScanner.
*/
private static final String[] DEFAULT_IMPORTS = new String[]{
// import all of the packages in helper
"me.lucko.helper",
// import all of the packages in bukkit
"org.bukkit",
// exclude craftbukkit classes
"-org.bukkit.craftbukkit",
// exclude helper-js dependencies (the classpath scanner itself)
"-me.lucko.helper.js.external"};

private ScriptController controller;
private ScriptEnvironment environment;

@Override
protected void enable() {
// load config
getLogger().info("Loading configuration...");
YamlConfiguration config = loadConfig("config.yml");

// search for packages which match the default import patterns
getLogger().info("Scanning the classpath to resolve default package imports...");
FastClasspathScanner classpathScanner = new FastClasspathScanner(DEFAULT_IMPORTS).strictWhitelist();

// add the classloaders for helper implementation plugins
LoaderUtils.getHelperImplementationPlugins().forEach(pl -> classpathScanner.addClassLoader(pl.getClass().getClassLoader()));

// form a list of matches packages
Set<String> defaultPackages = classpathScanner.scan()
.getNamesOfAllClasses()
.stream()
.map(className -> {
// convert to a package name
return className.substring(0, className.lastIndexOf('.'));
})
.collect(Collectors.toSet());

// setup the script controller
getLogger().info("Initialising script controller...");
this.controller = ScriptController.builder()
.logger(SystemLogger.usingJavaLogger(getLogger()))
.defaultEnvironmentSettings(EnvironmentSettings.builder()
.loadExecutor(this)
.runExecutor(Schedulers.sync())
.pollRate(Ticks.to(config.getLong("poll-interval", 20L), TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
.withBindings(new GeneralScriptBindings())
.withBindings(new HelperScriptBindings(this))
.withDefaultPackageImports(defaultPackages)
.build()
)
.build();

// get script directory
Path scriptDirectory = Paths.get(config.getString("script-directory"));
if (!Files.isDirectory(scriptDirectory)) {
Expand All @@ -62,39 +142,115 @@ protected void enable() {
}
}

getLogger().info("Using script directory: " + scriptDirectory.toString() + "(" + scriptDirectory.toAbsolutePath().toString() + ")");
// init a new environment for our scripts
getLogger().info("Creating new script environment at " + scriptDirectory.toString() + " (" + scriptDirectory.toAbsolutePath().toString() + ")");
this.environment = this.controller.setupNewEnvironment(scriptDirectory);

this.controller = ScriptController.builder()
.withDirectory(scriptDirectory)
.loadExecutor(new ScriptLoadingExecutor() {
@Override
public AutoCloseable scheduleAtFixedRate(Runnable runnable, long l, TimeUnit timeUnit) {
return Schedulers.builder()
.async()
.after(0L)
.every(l, timeUnit)
.run(runnable);
}

@Override
public void execute(@Nonnull Runnable command) {
Schedulers.async().run(command);
}
})
.runExecutor(Schedulers.sync())
.pollRate(Ticks.to(config.getLong("poll-interval", 20L), TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
.logger(new SystemLogger() {
@Override public void info(String s) { getLogger().info(s); }
@Override public void warning(String s) { getLogger().warning(s); }
@Override public void severe(String s) { getLogger().severe(s); }
})
.withBindings(new GeneralScriptBindings())
.withBindings(new HelperScriptBindings(this))
.build();
getLogger().info("Done!");
}

@Override
protected void disable() {
this.controller.shutdown();
}

@Override
public AutoCloseable scheduleAtFixedRate(Runnable runnable, long l, TimeUnit timeUnit) {
return Schedulers.builder()
.async()
.after(0L)
.every(l, timeUnit)
.run(runnable);
}

@Override
public void execute(@Nonnull Runnable command) {
Schedulers.async().run(command);
}

/**
* Some misc functions to help with using Java collections in JS
*/
public static class GeneralScriptBindings implements BindingsSupplier {
private static final Supplier<ArrayList> ARRAY_LIST = ArrayList::new;
private static final Supplier<LinkedList> LINKED_LIST = LinkedList::new;
private static final Supplier<HashSet> HASH_SET = HashSet::new;
private static final Supplier<HashMap> HASH_MAP = HashMap::new;
private static final Supplier<CopyOnWriteArrayList> COPY_ON_WRITE_ARRAY_LIST = CopyOnWriteArrayList::new;
private static final Supplier<Set> CONCURRENT_HASH_SET = ConcurrentHashMap::newKeySet;
private static final Supplier<ConcurrentHashMap> CONCURRENT_HASH_MAP = ConcurrentHashMap::new;
private static final Function<Object[], ArrayList> LIST_OF = objects -> new ArrayList<>(Arrays.asList(objects));
private static final Function<Object[], HashSet> SET_OF = objects -> new HashSet<>(Arrays.asList(objects));
private static final Function<Object[], ImmutableList> IMMUTABLE_LIST_OF = ImmutableList::copyOf;
private static final Function<Object[], ImmutableSet> IMMUTABLE_SET_OF = ImmutableSet::copyOf;
private static final Function<String, UUID> PARSE_UUID = s -> {
try {
return UUID.fromString(s);
} catch (IllegalArgumentException e) {
return null;
}
};

@Override
public void supplyBindings(Script script, BindingsBuilder bindings) {
bindings.put("newArrayList", ARRAY_LIST);
bindings.put("newLinkedList", LINKED_LIST);
bindings.put("newHashSet", HASH_SET);
bindings.put("newHashMap", HASH_MAP);
bindings.put("newCopyOnWriteArrayList", COPY_ON_WRITE_ARRAY_LIST);
bindings.put("newConcurrentHashSet", CONCURRENT_HASH_SET);
bindings.put("newConcurrentHashMap", CONCURRENT_HASH_MAP);
bindings.put("listOf", LIST_OF);
bindings.put("setOf", SET_OF);
bindings.put("immutableListOf", IMMUTABLE_LIST_OF);
bindings.put("immutableSetOf", IMMUTABLE_SET_OF);
bindings.put("parseUuid", PARSE_UUID);
}
}

/**
* Script bindings for helper utilities
*/
public static class HelperScriptBindings implements BindingsSupplier {
private final HelperJsPlugin plugin;

public HelperScriptBindings(HelperJsPlugin plugin) {
this.plugin = plugin;
}

@Override
public void supplyBindings(Script script, BindingsBuilder bindings) {
// provide a terminable registry
CompositeTerminable registry = CompositeTerminable.create();
script.getClosables().bind(registry);
bindings.put("registry", registry);

// provide core server classes
bindings.put("server", Bukkit.getServer());
bindings.put("plugin", this.plugin);
bindings.put("services", Bukkit.getServicesManager());

// some util functions
bindings.put("colorize", (Function<Object, String>) HelperScriptBindings::colorize);
bindings.put("newMetadataKey", (Function<Object, MetadataKey>) HelperScriptBindings::newMetadataKey);
bindings.put("newEmptyScheme", (Supplier<MenuScheme>) HelperScriptBindings::newScheme);
bindings.put("newScheme", (Function<SchemeMapping, MenuScheme>) HelperScriptBindings::newScheme);
}

private static String colorize(Object object) {
return Text.colorize(object.toString());
}

private static <T> MetadataKey<T> newMetadataKey(Object id) {
return MetadataKey.create(id.toString(), new TypeToken<T>(){});
}

private static MenuScheme newScheme() {
return new MenuScheme();
}

private static MenuScheme newScheme(SchemeMapping mapping) {
return new MenuScheme(mapping);
}
}
}

This file was deleted.

Loading

0 comments on commit 510b9bb

Please sign in to comment.