diff --git a/pom.xml b/pom.xml index e3035a2..122daf6 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 pw.yumc MiaoScript - 0.21.2 + 0.22.0 502647092 @@ -50,6 +50,8 @@ DEV + §622-05-21 §afeat: 优化 框架加载逻辑; + §622-05-20 §afeat: 调整 require 主包逻辑; §622-04-09 §afeat: 优化 引擎初始化逻辑;       §afeat: 优化 require 网络加载;       §afeat: 新增 JS 类型定义文件; @@ -204,7 +206,7 @@ org.spigotmc spigot-api - 1.17.1-R0.1-SNAPSHOT + 1.18.2-R0.1-SNAPSHOT compile diff --git a/src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java b/src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java index 69d065b..3bd0936 100644 --- a/src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java +++ b/src/main/java/pw/yumc/MiaoScript/api/MiaoScriptAPI.java @@ -8,7 +8,7 @@ import java.io.File; import java.nio.file.Paths; public class MiaoScriptAPI { - public static final String VERSION = "0.21.2"; + public static final String VERSION = "0.22.0"; private static String root; private static String libPath; private static ScriptEngine scriptEngine; diff --git a/src/main/java/pw/yumc/MiaoScript/api/loader/MavenDependLoader.java b/src/main/java/pw/yumc/MiaoScript/api/loader/MavenDependLoader.java index b5778b7..f4fcce8 100644 --- a/src/main/java/pw/yumc/MiaoScript/api/loader/MavenDependLoader.java +++ b/src/main/java/pw/yumc/MiaoScript/api/loader/MavenDependLoader.java @@ -55,7 +55,7 @@ public class MavenDependLoader { ext) ).openConnection(); connection.setConnectTimeout(5000); - connection.setReadTimeout(30000); + connection.setReadTimeout(120000); connection.setUseCaches(true); Files.copy(connection.getInputStream(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); } diff --git a/src/main/resources/bios.js b/src/main/resources/bios.js index 14b91cb..7c4d93e 100644 --- a/src/main/resources/bios.js +++ b/src/main/resources/bios.js @@ -27,7 +27,8 @@ var global = this; logger.info("ScriptEngine: " + ScriptEngineContextHolder.getEngine().getEngine().class.name) var future = new FutureTask(function () { Thread.currentThread().contextClassLoader = loader - load(System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger) + var faster = load(System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger) + return faster.default ? require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core')).default : false }) // Async Loading MiaoScript Engine new Thread(future, "MiaoScript thread").start() @@ -39,9 +40,11 @@ var global = this; logger.info("Waiting MiaoScript booted...") } // await polyfill loading - future.get() + // faster load core + var core = future.get() logger.info("MiaoScript booted starting...") - global.engineDisableImpl = require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core')).default || function () { + var disable = core ? core.enable() : require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core')).default + global.engineDisableImpl = disable || function () { logger.info('Error: abnormal Initialization MiaoScript Engine. Skip disable step...') } } @@ -60,8 +63,12 @@ var global = this; global.debug = true } if (Files.exists(Paths.get(root, "level"))) { - global.level = base.read(Paths.get(root, "level")) - logger.info('set system level to [' + global.level + ']...') + global.ScriptEngineLoggerLevel = base.read(Paths.get(root, "level")) + logger.info('found level set ScriptEngineLoggerLevel to ' + global.ScriptEngineLoggerLevel + '.') + } + if (Files.exists(Paths.get(root, "channel"))) { + global.ScriptEngineChannel = base.read(Paths.get(root, "channel")) + logger.info('found channel set ScriptEngineChannel to ' + global.ScriptEngineChannel + '.') } } diff --git a/src/main/resources/core/console.js b/src/main/resources/core/console.js index af7f91a..d9dbc3a 100644 --- a/src/main/resources/core/console.js +++ b/src/main/resources/core/console.js @@ -38,7 +38,7 @@ log: log, info: log, ex: log, - trace: global.level === "trace" ? _proxy('TRACE') : global.noop, + trace: global.ScriptEngineLoggerLevel === "trace" ? _proxy('TRACE') : global.noop, debug: global.debug ? logger.debug ? debug : _proxy('DEBUG') : global.noop, warn: _proxy('WARN'), error: _proxy('ERROR') diff --git a/src/main/resources/core/polyfill.js b/src/main/resources/core/polyfill.js index 56c6b01..d49de6d 100644 --- a/src/main/resources/core/polyfill.js +++ b/src/main/resources/core/polyfill.js @@ -5,6 +5,9 @@ * @param {any} logger */ function (root, logger) { + var System = Java.type('java.lang.System') + var Thread = Java.type('java.lang.Thread') + // Init Global Value global.root = root global.logger = logger @@ -21,9 +24,9 @@ } } // Init console and require - global.console = engineLoad(java.lang.System.getenv("MS_NODE_CORE_CONSOLE") || 'classpath:core/console.js')(logger) - console.log("Loading Engine at Thread", java.lang.Thread.currentThread().name) - global.require = engineLoad(java.lang.System.getenv("MS_NODE_CORE_REQUIRE") || 'classpath:core/require.js')(root) - require(global.scope + '/polyfill') + global.console = engineLoad(System.getenv("MS_NODE_CORE_CONSOLE") || 'classpath:core/console.js')(logger) + console.log("Loading Engine at Thread", Thread.currentThread().name) + global.require = engineLoad(System.getenv("MS_NODE_CORE_REQUIRE") || 'classpath:core/require.js')(root) + return require(global.scope + '/polyfill') } ) diff --git a/src/main/resources/core/require.js b/src/main/resources/core/require.js index 87e332d..75a3b2b 100644 --- a/src/main/resources/core/require.js +++ b/src/main/resources/core/require.js @@ -54,7 +54,12 @@ var MS_NODE_PATH = System.getenv("MS_NODE_PATH") || root + separatorChar + 'node_modules' var MS_NODE_REGISTRY = System.getenv("MS_NODE_REGISTRY") || 'https://registry.npmmirror.com' - var FALLBACK_NODE_REGISTRY = System.getenv("FALLBACK_NODE_REGISTRY") || 'https://repo.yumc.pw/repository/npm' + var MS_FALLBACK_NODE_REGISTRY = System.getenv("MS_FALLBACK_NODE_REGISTRY") || 'https://repo.yumc.pw/repository/npm' + var MS_NETWORK_CONNECT_TIMEOUT = System.getenv("MS_NETWORK_CONNECT_TIMEOUT") || 5000 + var MS_NETWORK_READ_TIMEOUT = System.getenv("MS_NETWORK_TIMEOUT") || 45000 + var MS_NETWORK_DOWNLOAD_TIMEOUT = System.getenv("MS_NETWORK_DOWNLOAD_TIMEOUT") || 60000 + var MS_NETWORK_USE_CACHES = System.getenv("MS_NETWORK_USE_CACHES") || true + var CoreModules = [ "assert", "async_hooks", "Buffer", "child_process", "cluster", "crypto", "dgram", "dns", "domain", "events", "fs", "http", "http2", "https", @@ -109,6 +114,11 @@ return file.absolutePath } + function __error(message) { + console.error(message) + return new Error(message) + } + /** * 解析模块名称为文件 * 按照下列顺序查找 @@ -168,9 +178,13 @@ dir = dir !== undefined ? new File(dir, file) : new File(file) var _package = new File(dir, 'package.json') if (_package.exists()) { - var json = JSON.parse(base.read(_package)) - if (json.main) { - return resolveAsFile(json.main, dir) + try { + var json = JSON.parse(base.read(_package)) + if (json.main) { + return resolveAsFile(json.main, dir) + } + } catch (error) { + throw __error('resolveAsDirectory ' + dir + ' package.json error ' + error) } } // if no package or package.main exists, look for index.js @@ -217,13 +231,13 @@ var filename = file.name var lastDotIndexOf = filename.lastIndexOf('.') if (lastDotIndexOf == -1) { - throw Error('require ' + file + ' error: module must include file ext.') + throw __error('require ' + file + ' error: module must include file ext.') } var name = filename.substring(0, lastDotIndexOf) var ext = filename.substring(lastDotIndexOf + 1) var loader = requireLoaders[ext] if (!loader) { - throw Error('Unsupported module ' + filename + '. require loader not found.') + throw __error('Unsupported module ' + filename + '. require loader not found.') } console.trace('Loading module', name + '(' + id + ')', 'Optional', JSON.stringify(optional)) var module = { @@ -295,42 +309,98 @@ return module } + /** + * 获得网络链接 + * @param {string} url 网址 + */ + function getConnection(url) { + var connection = new URL(url).openConnection() + connection.setConnectTimeout(MS_NETWORK_CONNECT_TIMEOUT) + connection.setReadTimeout(MS_NETWORK_READ_TIMEOUT) + connection.setUseCaches(MS_NETWORK_USE_CACHES) + return connection + } + + /** + * 获得网络流 + * @param {string} url 网址 + */ + function getConnectionStream(url) { + var connection = getConnection(url) + return connection.getInputStream() + } + + function splitVersionFromName(name) { + // process package name + // es6-map/implement => [es6-map/implement, undefined] + // @ccms/common/dist/reflect => [@ccms/common, undefined] + var name_arr = name.split('/') + var module_name = '' + var module_version = '' + if (name.startsWith('@')) { + var module_version_arr = name_arr[1].split('@') + module_name = name_arr[0] + '/' + module_version_arr[0] + } else { + var module_version_arr = name_arr[0].split('@') + module_name = module_version_arr[0] + } + // handle internal package version + if (name.startsWith(global.scope) && global.ScriptEngineChannel) { + module_version = global.ScriptEngineChannel + } else { + module_version = module_version_arr[1] + } + return [module_name, module_version] + } + /** * 尝试从网络下载依赖包 * @param {string} name 包名称 */ - function download(name) { - // process package name - // es6-map/implement => es6-map - // @ccms/common/dist/reflect => @ccms/common - var name_arr = name.split('/') - var module_name = name.startsWith('@') ? name_arr[0] + '/' + name_arr[1] : name_arr[0] - var target = MS_NODE_PATH + separatorChar + module_name - var _package = new File(target, 'package.json') - if (_package.exists()) { return name } - // at windows need replace file name java.lang.IllegalArgumentException: Invalid prefix or suffix - var info = fetchPackageInfo(module_name) - var latest_version = info['dist-tags']['latest'] - var version = ModulesVersionLock[module_name] || latest_version - var _version = info.versions[version] || info.versions[latest_version] - var url = _version.dist.tarball - console.log('fetch node_module ' + module_name + ' version ' + version + ' waiting...') - return executor.submit(new Callable(function () { - var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(new URL(url).openStream()))) - var entry - while ((entry = tis.getNextEntry()) != null) { - var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8)) - var parentFile = targetPath.toFile().getParentFile() - if (!parentFile.isDirectory()) { - parentFile.delete() - parentFile.mkdirs() - } - Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING) + function download(name, optional, retry) { + var name_arr = splitVersionFromName(name) + var module_name = name_arr[0] + var module_version = name_arr[1] + try { + var target = MS_NODE_PATH + separatorChar + module_name + var _package = new File(target, 'package.json') + if (_package.exists()) { return name } + var info = fetchPackageInfo(module_name) + if (!module_version) { + // if not special version get from lock or tag + module_version = ModulesVersionLock[module_name] || info['dist-tags']['latest'] + } else if (!/\d+\.\d+\.\w+/.test(module_version)) { + // maybe module_version = latest + module_version = info['dist-tags'][module_version] } - return name - })) - // default wait 45 seconds - .get(45, TimeUnit.SECONDS) + var _version = info.versions[module_version] + if (!_version) { + throw __error('fetch node_module ' + module_name + ' version ' + module_version + ' failed. can\t found tarball from versions.') + } + var url = _version.dist.tarball + console.log('fetch node_module ' + module_name + ' version ' + module_version + ' waiting...') + return executor.submit(new Callable(function () { + var tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(getConnectionStream(url)))) + var entry + while ((entry = tis.getNextEntry()) != null) { + var targetPath = Paths.get(target + separatorChar + entry.getName().substring(8)) + var parentFile = targetPath.toFile().getParentFile() + if (!parentFile.isDirectory()) { + parentFile.delete() + parentFile.mkdirs() + } + Files.copy(tis, targetPath, StandardCopyOption.REPLACE_EXISTING) + } + return name + })).get(MS_NETWORK_DOWNLOAD_TIMEOUT, TimeUnit.SECONDS) + } catch (error) { + retry = retry || 1 + if (retry > 3) { + throw __error('fetch node_module ' + module_name + ' version ' + module_version + ' failed. greater than 3 times stop retry.') + } + console.log('fetch node_module ' + module_name + ' version ' + module_version + ' failed retrying...') + return download(name, optional, ++retry) + } } /** @@ -341,16 +411,19 @@ try { content = fetchContent(MS_NODE_REGISTRY + '/' + module_name) } catch (ex) { - console.warn('can\'t fetch package ' + module_name + ' from ' + MS_NODE_REGISTRY + ' registry. try fetch from ' + FALLBACK_NODE_REGISTRY + ' registry...') - content = fetchContent(FALLBACK_NODE_REGISTRY + '/' + module_name) + console.warn('can\'t fetch package ' + module_name + ' from ' + MS_NODE_REGISTRY + ' registry. try fetch from ' + MS_FALLBACK_NODE_REGISTRY + ' registry...') + content = fetchContent(MS_FALLBACK_NODE_REGISTRY + '/' + module_name) } return JSON.parse(content) } + /** + * 获取网络内容 + * @param {string} url 网址 + */ function fetchContent(url, timeout) { - timeout = timeout || 10 return executor.submit(new Callable(function fetchContent() { - var input = new URL(url).openStream() + var input = getConnectionStream(url) var output = new ByteArrayOutputStream() var buffer = new ByteArray(1024) try { @@ -363,7 +436,7 @@ input.close() output.close() } - })).get(timeout, TimeUnit.SECONDS) + })).get(timeout || MS_NETWORK_READ_TIMEOUT, TimeUnit.SECONDS) } var lastModule = '' @@ -385,7 +458,7 @@ if (resolve(newName, path, optional) !== undefined) { return newName } - throw new Error("Can't load nodejs core module " + name + " . maybe later will auto replace to " + global.scope + "/nodejs/" + name + ' to compatible...') + throw __error("Can't load nodejs core module " + name + " . maybe later will auto replace to " + global.scope + "/nodejs/" + name + ' to compatible...') } return name } @@ -422,10 +495,10 @@ if ((file = resolve(name, path, optional)) === undefined) { // excloud local dir, prevent too many recursive call and cache not found module if (optional.local || optional.recursive || notFoundModules[name]) { - throw new Error("Can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!') + throw __error("Can't found module " + name + '(' + JSON.stringify(optional) + ') at local ' + path + ' or network!') } optional.recursive = true - return _require(download(name), path, optional) + return _require(download(name, optional), path, optional) } setCacheModule(file, optional) return _requireFile(file, optional) @@ -465,7 +538,7 @@ */ return function __DynamicRequire__(path, optional) { if (!path) { - throw new Error('require path can\'t be undefined or empty!') + throw __error('require path can\'t be undefined or empty!') } return _require(path, parent, __assign({ cache: true, @@ -574,14 +647,14 @@ console.info('Require module env list:') console.info('- MS_NODE_PATH:', MS_NODE_PATH.startsWith(root) ? MS_NODE_PATH.split(root)[1] : MS_NODE_PATH) console.info('- MS_NODE_REGISTRY:', MS_NODE_REGISTRY) - console.info('- FALLBACK_NODE_REGISTRY:', FALLBACK_NODE_REGISTRY) + console.info('- MS_FALLBACK_NODE_REGISTRY:', MS_FALLBACK_NODE_REGISTRY) } function initCacheModuleIds() { try { cacheModuleIds = JSON.parse(base.read(cacheModuleIdsFile)) if (cacheModuleIds['@ccms-cache-module-root'] != MS_NODE_PATH) { - throw new Error('canonicalRoot Change ' + cacheModuleIds['@ccms-cache-module-root'] + ' to ' + MS_NODE_PATH + ' Clear Cache!') + throw __error('canonicalRoot Change ' + cacheModuleIds['@ccms-cache-module-root'] + ' to ' + MS_NODE_PATH + ' Clear Cache!') } console.log('Read cacheModuleIds from file', cacheModuleIdsFile.startsWith(root) ? cacheModuleIdsFile.split(root)[1] : cacheModuleIdsFile) } catch (error) { @@ -594,7 +667,7 @@ function initVersionLock() { try { var version_lock_url = 'https://ms.yumc.pw/api/plugin/download/name/version_lock' + (global.debug ? '-debug' : '') - ModulesVersionLock = JSON.parse(fetchContent(version_lock_url, 5)) + ModulesVersionLock = JSON.parse(fetchContent(version_lock_url, 5000)) try { ModulesVersionLock = __assign(ModulesVersionLock, JSON.parse(base.read(localVersionLockFile))) } catch (e) { @@ -616,7 +689,7 @@ registerLoader('json', compileJson) try { engineLoad({ - script: fetchContent('https://ms.yumc.pw/api/plugin/download/name/require_loader', 5), + script: fetchContent('https://ms.yumc.pw/api/plugin/download/name/require_loader', 5000), name: 'core/require_loader.js' })(require) } catch (error) {