From a4999745de1d28bc42fd57ab45daea097a164c13 Mon Sep 17 00:00:00 2001 From: walterhiggins Date: Tue, 14 Jan 2014 22:54:49 +0000 Subject: [PATCH] Added config.yml for plugin configuration - issue #102 --- build.xml | 35 +++++- .../scriptcraft/ScriptCraftPlugin.java | 105 +----------------- src/main/javascript/lib/events.js | 13 ++- src/main/javascript/lib/plugin.js | 4 +- src/main/javascript/lib/require.js | 31 ++---- src/main/javascript/lib/scriptcraft.js | 36 +++--- src/main/resources/boot.js | 76 +++++++++++++ src/main/resources/config.yml | 4 + 8 files changed, 161 insertions(+), 143 deletions(-) create mode 100644 src/main/resources/boot.js create mode 100644 src/main/resources/config.yml diff --git a/build.xml b/build.xml index 22c4f74..2338a24 100644 --- a/build.xml +++ b/build.xml @@ -19,6 +19,9 @@ + + + @@ -119,17 +122,39 @@ Walter Higgins - - - - + + + + + + + + + + + + + + + + + + - + + + [[version]] diff --git a/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java b/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java index 6d6b16e..8fb5a71 100644 --- a/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java +++ b/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java @@ -1,20 +1,12 @@ package net.walterhiggins.scriptcraft; -import java.io.File; -import java.io.FileReader; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.InputStreamReader; import javax.script.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.Collection; -import java.util.Arrays; import java.util.List; import java.util.ArrayList; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.command.*; -import org.bukkit.Bukkit; import org.bukkit.event.Listener; public class ScriptCraftPlugin extends JavaPlugin implements Listener @@ -23,114 +15,27 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener // need to look at possibly having context/scope per operator //protected Map playerContexts = new HashMap(); protected ScriptEngine engine = null; - private static final String JS_PLUGINS_DIR = "plugins/scriptcraft"; - private static final String JS_PLUGINS_ZIP = "scriptcraft.zip"; - - /** - * Unzips bundled javascript code. - */ - private void unzipJS() throws IOException - { - // - // does the js-plugins directory exist? - // - File jsPlugins = new File(JS_PLUGINS_DIR); - if (!jsPlugins.exists()) - { - getLogger().info("Directory " + jsPlugins.getCanonicalPath() + " does not exist."); - getLogger().info("Initializing " + jsPlugins.getCanonicalPath() + " directory with contents from plugin archive."); - try{ - jsPlugins.mkdirs(); - }catch(Exception e){ - throw new RuntimeException("Failed to create directory " + jsPlugins.getCanonicalPath() + ":" + e.getMessage()); - } - } - - ZipInputStream zis = new ZipInputStream(getResource(JS_PLUGINS_ZIP)); - ZipEntry entry; - try { - while ( ( entry = zis.getNextEntry() ) != null) - { - String filename = entry.getName(); - - File newFile = new File(jsPlugins, filename); - - //create all non exists folders - //else you will hit FileNotFoundException for compressed folder - if (entry.isDirectory()){ - newFile.mkdirs(); - }else{ - // - // only write out to file if zip entry is newer than file - // - String reason = null; - long zTime = entry.getTime(); - boolean unzip = false; - if (!newFile.exists()){ - reason = "NE"; - unzip = true; - } - else{ - long fTime = newFile.lastModified(); - if (zTime > fTime){ - reason = "" + new Long((zTime-fTime)/3600000) + "h"; - unzip = true; - } - - } - if (unzip){ - getLogger().info("Unzipping " + newFile.getCanonicalPath() + " (" + reason + ")" ); - FileOutputStream fout = new FileOutputStream(newFile); - for (int c = zis.read(); c != -1; c = zis.read()) { - fout.write(c); - } - fout.close(); - } - - } - zis.closeEntry(); - } - zis.close(); - }catch (IOException ioe){ - getLogger().warning(ioe.getMessage()); - ioe.printStackTrace(); - } - } @Override public void onEnable() { - FileReader reader = null; try{ - unzipJS(); + ScriptEngineManager factory = new ScriptEngineManager(); - File bootScript = new File(JS_PLUGINS_DIR + "/lib/scriptcraft.js"); this.engine = factory.getEngineByName("JavaScript"); - reader = new FileReader(bootScript); - this.engine.eval(reader); Invocable inv = (Invocable)this.engine; - inv.invokeFunction("__onEnable", engine, this, bootScript); - + this.engine.eval(new InputStreamReader(this.getResource("boot.js"))); + inv.invokeFunction("__scboot", this, engine); + }catch(Exception e){ e.printStackTrace(); this.getLogger().severe(e.getMessage()); - }finally { - if (reader != null){ - try { - reader.close(); - }catch(IOException ioe){ - // fail silently - } - } } } public List onTabComplete(CommandSender sender, Command cmd, String alias, String[] args) { - // - // delegate to javascript - // List result = new ArrayList(); try { Invocable inv = (Invocable)this.engine; diff --git a/src/main/javascript/lib/events.js b/src/main/javascript/lib/events.js index 651b1f5..63f8b88 100644 --- a/src/main/javascript/lib/events.js +++ b/src/main/javascript/lib/events.js @@ -93,7 +93,18 @@ exports.on = function( priority = bkEvent.EventPriority[priority]; } if (typeof eventType == "string"){ - eventType = eval('org.bukkit.event.' + eventType); + /* + Nashorn doesn't support bracket notation for accessing packages. + E.g. java.net will work but java['net'] won't. + + https://bugs.openjdk.java.net/browse/JDK-8031715 + */ + if (typeof Java != 'undefined'){ + // nashorn environment + eventType = Java.type('org.bukkit.event.' + eventType); + } else { + eventType = eval('org.bukkit.event.' + eventType); + } } var handlerList = eventType.getHandlerList(); var listener = {}; diff --git a/src/main/javascript/lib/plugin.js b/src/main/javascript/lib/plugin.js index ba9c9ab..fe493f6 100644 --- a/src/main/javascript/lib/plugin.js +++ b/src/main/javascript/lib/plugin.js @@ -49,6 +49,8 @@ exports.autoload = function(dir) { var _listSourceFiles = function(store,dir) { var files = dir.listFiles(); + if (!files) + return; for (var i = 0;i < files.length; i++) { var file = files[i]; if (file.isDirectory()){ @@ -73,8 +75,6 @@ exports.autoload = function(dir) { console.info(len + ' scriptcraft plugins found.'); for (var i = 0;i < len; i++){ var pluginPath = _canonize(sourceFiles[i]); - if (config.verbose) - console.info('Loading plugin: ' + pluginPath); var module = {}; try { module = require(pluginPath); diff --git a/src/main/javascript/lib/require.js b/src/main/javascript/lib/require.js index fa3feaf..1e3d2ba 100644 --- a/src/main/javascript/lib/require.js +++ b/src/main/javascript/lib/require.js @@ -54,12 +54,7 @@ module specification, the '.js' suffix is optional. [cjsmodules]: http://wiki.commonjs.org/wiki/Modules/1.1.1. ***/ -(function (logger, evaluator, verbose, rootDir, modulePaths) { - - if (verbose){ - logger.info("Setting up 'require' module system. Root Directory: " + rootDir); - logger.info("Module paths: " + JSON.stringify(modulePaths)); - } +(function (rootDir, modulePaths, hooks) { var File = java.io.File; @@ -152,9 +147,6 @@ When resolving module names to file paths, ScriptCraft uses the following rules. if (resolvedFile.exists()) return resolvedFile; } - if (verbose){ - logger.info("Module " + moduleName + " not found in " + modulePaths[i]); - } } } else { // it's of the form ./path @@ -192,8 +184,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules. if (! ( (''+path).match(/^\./) )){ errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths); } - logger.warning(errMsg); - throw new Error(errMsg); + throw errMsg; } var canonizedFilename = _canonize(file); @@ -201,9 +192,8 @@ When resolving module names to file paths, ScriptCraft uses the following rules. if (moduleInfo){ return moduleInfo; } - if (verbose){ - logger.info("loading module " + canonizedFilename); - } + if (hooks) + hooks.loading(canonizedFilename); var reader = new java.io.FileReader(file); var br = new java.io.BufferedReader(reader); var code = ""; @@ -225,10 +215,9 @@ When resolving module names to file paths, ScriptCraft uses the following rules. _loadedModules[canonizedFilename] = moduleInfo; var compiledWrapper = null; try { - compiledWrapper = evaluator.eval(code); + compiledWrapper = eval(code); }catch (e){ - logger.severe("Error:" + e + " while evaluating module " + canonizedFilename); - throw e; + throw "Error:" + e + " while evaluating module " + canonizedFilename; } var __dirname = "" + file.parentFile.canonicalPath; var parameters = [ @@ -243,12 +232,10 @@ When resolving module names to file paths, ScriptCraft uses the following rules. .apply(moduleInfo.exports, /* this */ parameters); } catch (e){ - logger.severe('Error:' + e + ' while executing module ' + canonizedFilename); - throw e; + throw 'Error:' + e + ' while executing module ' + canonizedFilename; } - if (verbose) - logger.info("loaded module " + canonizedFilename); - + if (hooks) + hooks.loaded(canonizedFilename); moduleInfo.loaded = true; return moduleInfo; }; diff --git a/src/main/javascript/lib/scriptcraft.js b/src/main/javascript/lib/scriptcraft.js index 9588338..84dad7d 100644 --- a/src/main/javascript/lib/scriptcraft.js +++ b/src/main/javascript/lib/scriptcraft.js @@ -428,6 +428,7 @@ function __onEnable (__engine, __plugin, __script) var libDir = __script.parentFile; // lib (assumes scriptcraft.js is in craftbukkit/plugins/scriptcraft/lib directory var jsPluginsRootDir = libDir.parentFile; // scriptcraft var jsPluginsRootDirName = _canonize(jsPluginsRootDir); + var logger = __plugin.logger; /* Save a javascript object to a file (saves using JSON notation) @@ -482,7 +483,7 @@ function __onEnable (__engine, __plugin, __script) result = __engine.eval(wrappedCode); // issue #103 avoid side-effects of || operator on Mac Rhino }catch (e){ - __plugin.logger.severe("Error evaluating " + canonizedFilename + ", " + e ); + logger.severe("Error evaluating " + canonizedFilename + ", " + e ); } finally { try { @@ -493,7 +494,7 @@ function __onEnable (__engine, __plugin, __script) } }else{ if (warnOnFileNotFound) - __plugin.logger.warning(canonizedFilename + " not found"); + logger.warning(canonizedFilename + " not found"); } return result; }; @@ -529,7 +530,6 @@ function __onEnable (__engine, __plugin, __script) }; var _echo = function (msg) { - __plugin.logger.info( msg ); if (typeof self == "undefined"){ return; } @@ -543,17 +543,28 @@ function __onEnable (__engine, __plugin, __script) global.addUnloadHandler = _addUnloadHandler; - var fnRequire = _load(jsPluginsRootDirName + '/lib/require.js',true); + var configRequire = _load(jsPluginsRootDirName + '/lib/require.js',true); /* setup paths to search for modules */ var modulePaths = [jsPluginsRootDirName + '/lib/', jsPluginsRootDirName + '/modules/']; - global.require = fnRequire(__plugin.logger, - __engine, - config.verbose, - jsPluginsRootDirName, - modulePaths); + + if (config.verbose){ + logger.info('Setting up CommonJS-style module system. Root Directory: ' + jsPluginsRootDirName); + logger.info('Module paths: ' + JSON.stringify(modulePaths)); + } + var requireHooks = { + loading: function(path){ + if (config.verbose) + logger.info('loading ' + path); + }, + loaded: function(path){ + if (config.verbose) + logger.info('loaded ' + path); + } + }; + global.require = configRequire(jsPluginsRootDirName, modulePaths,requireHooks ); require('js-patch')(global); global.console = require('console'); @@ -570,10 +581,10 @@ function __onEnable (__engine, __plugin, __script) var events = require('events'); events.on('server.PluginDisableEvent',function(l,e){ // save config - _save(global.config, new File(jsPluginsRootDir, "data/global-config.json" )); + _save(global.config, new File(jsPluginsRootDir, 'data/global-config.json' )); _runUnloadHandlers(); - org.bukkit.event.HandlerList["unregisterAll(org.bukkit.plugin.Plugin)"](__plugin); + org.bukkit.event.HandlerList['unregisterAll(org.bukkit.plugin.Plugin)'](__plugin); }); // wph 20131226 - make events global as it is used by many plugins/modules global.events = events; @@ -593,12 +604,11 @@ function __onEnable (__engine, __plugin, __script) global.self = sender; global.__engine = __engine; try { - //var jsResult = __engine["eval(java.lang.String,javax.script.Bindings)"]( fnBody, bindings ); var jsResult = __engine.eval(fnBody); if (jsResult) sender.sendMessage(jsResult); }catch (e){ - __plugin.logger.severe("Error while trying to evaluate javascript: " + fnBody + ", Error: "+ e); + logger.severe("Error while trying to evaluate javascript: " + fnBody + ", Error: "+ e); throw e; }finally{ delete global.self; diff --git a/src/main/resources/boot.js b/src/main/resources/boot.js new file mode 100644 index 0000000..5cdd1d6 --- /dev/null +++ b/src/main/resources/boot.js @@ -0,0 +1,76 @@ +/* + This file is the first and only file executed directly from the Java Plugin. +*/ +var __scboot = null; +(function(){ + var File = java.io.File + ,FileReader = java.io.FileReader + ,FileOutputStream = java.io.FileOutputStream + ,ZipInputStream = java.util.zip.ZipInputStream + ,jsPlugins = new File('plugins/scriptcraft') + ,initScript = 'lib/scriptcraft.js'; + + var unzip = function(path, logger, plugin) { + var zis = new ZipInputStream(plugin.getResource(path)) + , entry , reason = null, unzipFile = false, zTime = 0 + , fTime = 0, fout = null, c, newFile; + + while ( ( entry = zis.nextEntry ) != null ) { + + newFile = new File(jsPlugins, entry.name); + if (entry.isDirectory()){ + newFile.mkdirs(); + zis.closeEntry(); + continue; + } + reason = null; + zTime = entry.time; + unzipFile = false; + if (!newFile.exists()) { + reason = 'NE'; + unzipFile = true; + }else{ + fTime = newFile.lastModified(); + if (zTime > fTime) { + reason = ((zTime - fTime) / 3600000) + "h"; + unzipFile = true; + } + } + if (unzipFile) { + logger.info('Unzipping ' + newFile.canonicalPath + ' (' + reason + ')' ); + fout = new FileOutputStream(newFile); + for (c = zis.read(); c != -1; c = zis.read()) { + fout.write(c); + } + fout.close(); + } + zis.closeEntry(); + } + zis.close(); + }; + + __scboot = function ( plugin, engine ) + { + var logger = plugin.logger, cfg = plugin.config + ,cfgName, initScriptFile = new File(jsPlugins,initScript) + ,zips = ['lib','plugins','modules'] + ,i = 0 ,len = zips.length; + + if (!jsPlugins.exists()){ + logger.info('Directory ' + jsPlugins.canonicalPath + ' does not exist.'); + logger.info('Initializing ' + jsPlugins.canonicalPath + ' directory with contents from plugin archive.'); + jsPlugins.mkdirs(); + } + + for (i = 0; i < len;i++){ + cfgName = 'extract-js.' + zips[i]; + if (cfg.getBoolean(cfgName)){ + unzip( zips[i] + '.zip',logger,plugin); + } + } + plugin.saveDefaultConfig(); + + engine.eval(new FileReader(initScriptFile)); + __onEnable(engine, plugin, initScriptFile); + }; +})(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..96d7c0f --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,4 @@ +extract-js: + plugins: true + modules: true + lib: true