Merge pull request #19 from 577fkj/main

Support the latest Grasscutter
This commit is contained in:
Mingjun Yin 2022-09-29 12:17:41 -07:00 committed by GitHub
commit 5b11632e97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 84 deletions

View File

@ -1,6 +1,7 @@
package com.mojo.consoleplus; package com.mojo.consoleplus;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojo.consoleplus.command.PluginCommand; import com.mojo.consoleplus.command.PluginCommand;
import com.mojo.consoleplus.config.MojoConfig; import com.mojo.consoleplus.config.MojoConfig;
import com.mojo.consoleplus.socket.SocketClient; import com.mojo.consoleplus.socket.SocketClient;
@ -27,6 +28,7 @@ public class ConsolePlus extends Plugin {
public static MojoConfig config = MojoConfig.loadConfig(); public static MojoConfig config = MojoConfig.loadConfig();
public static String versionTag; public static String versionTag;
public static AuthHandler authHandler; public static AuthHandler authHandler;
public static Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Override @Override
public void onLoad() { public void onLoad() {
@ -52,7 +54,11 @@ public class ConsolePlus extends Plugin {
folder.mkdirs(); folder.mkdirs();
} }
if (!config.UseCDN) { if (!config.UseCDN) {
Grasscutter.getHttpServer().getHandle().config.addStaticFiles("/mojoplus", folder_name, Location.EXTERNAL); Grasscutter.getHttpServer().getHandle()._conf.addStaticFiles(staticFileConfig -> {
staticFileConfig.hostedPath = "/mojoplus";
staticFileConfig.directory = folder_name;
staticFileConfig.location = Location.EXTERNAL;
});
} else { } else {
if (!HTTP_POLICIES.cors.enabled) { if (!HTTP_POLICIES.cors.enabled) {
Grasscutter.getLogger().error("[MojoConsole] You enabled the useCDN option, in this option, you have to configure Grasscutter accept CORS request. See `config.json`->`server`->`policies`->`cors`."); Grasscutter.getLogger().error("[MojoConsole] You enabled the useCDN option, in this option, you have to configure Grasscutter accept CORS request. See `config.json`->`server`->`policies`->`cors`.");

View File

@ -1,47 +1,38 @@
package com.mojo.consoleplus; package com.mojo.consoleplus;
import static java.lang.Integer.parseInt; import com.mojo.consoleplus.command.PluginCommand;
import static java.lang.Long.parseLong; import com.mojo.consoleplus.forms.RequestAuth;
import com.mojo.consoleplus.forms.RequestJson;
import com.mojo.consoleplus.forms.ResponseAuth;
import com.mojo.consoleplus.forms.ResponseJson;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.CommandMap;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.server.http.Router;
import emu.grasscutter.utils.MessageHandler;
import io.javalin.Javalin;
import io.javalin.http.Context;
import java.io.IOException; import java.io.IOException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import emu.grasscutter.Grasscutter; import static java.lang.Integer.parseInt;
import emu.grasscutter.command.CommandMap; import static java.lang.Long.parseLong;
import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.Account;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.utils.MessageHandler;
import express.http.Request;
import express.http.Response;
import express.Express;
import emu.grasscutter.server.http.Router;
import io.javalin.Javalin;
import com.mojo.consoleplus.forms.RequestAuth;
// import com.google.gson.Gson;
// import com.google.gson.GsonBuilder;
import com.mojo.consoleplus.forms.RequestJson;
import com.mojo.consoleplus.forms.ResponseAuth;
import com.mojo.consoleplus.forms.ResponseJson;
import com.mojo.consoleplus.command.PluginCommand;
public final class RequestHandler implements Router { public final class RequestHandler implements Router {
// private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); // private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Override public void applyRoutes(Express app, Javalin handle) { @Override public void applyRoutes(Javalin javalin) {
app.post("/mojoplus/api", RequestHandler::processRequest); javalin.post("/mojoplus/api", RequestHandler::processRequest);
app.post("/mojoplus/auth", RequestHandler::requestKey); javalin.post("/mojoplus/auth", RequestHandler::requestKey);
} }
public static void processRequest(Request req, Response res) throws IOException { public static void processRequest(Context context) {
RequestJson request = req.body(RequestJson.class); RequestJson request = context.bodyAsClass(RequestJson.class);
res.type("application/json");
Player player = null; Player player = null;
if (request.k2 != null) { // version 2 token if (request.k2 != null) { // version 2 token
@ -70,39 +61,38 @@ public final class RequestHandler implements Router {
// TODO: Enable execut commands to third party // TODO: Enable execut commands to third party
CommandMap.getInstance().invoke(player, player, request.payload); CommandMap.getInstance().invoke(player, player, request.payload);
} catch (Exception e) { } catch (Exception e) {
res.json(new ResponseJson("error", 500, e.getStackTrace().toString())); context.json(new ResponseJson("error", 500, e.getStackTrace().toString()));
break; break;
} }
case "ping": case "ping":
// res.json(new ResponseJson("success", 200)); // res.json(new ResponseJson("success", 200));
res.json(new ResponseJson("success", 200, resultCollector.getMessage())); context.json(new ResponseJson("success", 200, resultCollector.getMessage()));
break; break;
default: default:
res.json(new ResponseJson("400 Bad Request", 400)); context.json(new ResponseJson("400 Bad Request", 400));
break; break;
} }
player.setMessageHandler(null); player.setMessageHandler(null);
return; return;
} }
res.json(new ResponseJson("403 Forbidden", 403)); context.json(new ResponseJson("403 Forbidden", 403));
} }
public static void requestKey(Request req, Response res) throws IOException { public static void requestKey(Context context) throws IOException {
RequestAuth request = req.body(RequestAuth.class); RequestAuth request = context.bodyAsClass(RequestAuth.class);
if (request.otp != null && !request.otp.equals("")) { if (request.otp != null && !request.otp.equals("")) {
if (PluginCommand.getInstance().tickets.get(request.otp) == null) { if (PluginCommand.getInstance().tickets.get(request.otp) == null) {
res.json(new ResponseAuth(404, "Not found", null)); context.json(new ResponseAuth(404, "Not found", null));
return; return;
} }
String key = PluginCommand.getInstance().tickets.get(request.otp).key; String key = PluginCommand.getInstance().tickets.get(request.otp).key;
if (key == null){ if (key == null){
res.json(new ResponseAuth(403, "Not ready yet", null)); context.json(new ResponseAuth(403, "Not ready yet", null));
} else { } else {
PluginCommand.getInstance().tickets.remove(request.otp); PluginCommand.getInstance().tickets.remove(request.otp);
res.json(new ResponseAuth(200, "", key)); context.json(new ResponseAuth(200, "", key));
} }
return;
} else if (request.uid != 0) { } else if (request.uid != 0) {
String otp = new DecimalFormat("000000").format(new Random().nextInt(999999)); String otp = new DecimalFormat("000000").format(new Random().nextInt(999999));
while (PluginCommand.getInstance().tickets.containsKey(otp)){ while (PluginCommand.getInstance().tickets.containsKey(otp)){
@ -116,12 +106,11 @@ public final class RequestHandler implements Router {
} }
} }
if (targetPlayer == null){ if (targetPlayer == null){
res.json(new ResponseAuth(404, "Not found", null)); context.json(new ResponseAuth(404, "Not found", null));
return; return;
} }
PluginCommand.getInstance().tickets.put(otp, new PluginCommand.Ticket(targetPlayer, System.currentTimeMillis()/ 1000 + 300, true)); PluginCommand.getInstance().tickets.put(otp, new PluginCommand.Ticket(targetPlayer, System.currentTimeMillis()/ 1000 + 300, true));
res.json(new ResponseAuth(201, "Code generated", otp)); context.json(new ResponseAuth(201, "Code generated", otp));
return;
} }
} }
} }

View File

@ -12,17 +12,11 @@ import com.mojo.consoleplus.socket.packet.HttpPacket;
import com.mojo.consoleplus.socket.packet.OtpPacket; import com.mojo.consoleplus.socket.packet.OtpPacket;
import com.mojo.consoleplus.socket.packet.player.Player; import com.mojo.consoleplus.socket.packet.player.Player;
import com.mojo.consoleplus.socket.packet.player.PlayerEnum; import com.mojo.consoleplus.socket.packet.player.PlayerEnum;
import com.mojo.consoleplus.socket.packet.player.PlayerList;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.server.http.Router; import emu.grasscutter.server.http.Router;
import express.Express;
import express.http.Request;
import express.http.Response;
import io.javalin.Javalin; import io.javalin.Javalin;
import io.javalin.http.Context;
import java.io.IOException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.Map;
import java.util.Random; import java.util.Random;
import static java.lang.Integer.parseInt; import static java.lang.Integer.parseInt;
@ -32,15 +26,14 @@ import static java.lang.Long.parseLong;
public final class RequestOnlyHttpHandler implements Router { public final class RequestOnlyHttpHandler implements Router {
// private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); // private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
@Override public void applyRoutes(Express app, Javalin handle) { @Override public void applyRoutes(Javalin javalin) {
app.post("/mojoplus/api", RequestOnlyHttpHandler::processRequest); javalin.post("/mojoplus/api", RequestOnlyHttpHandler::processRequest);
app.post("/mojoplus/auth", RequestOnlyHttpHandler::requestKey); javalin.post("/mojoplus/auth", RequestOnlyHttpHandler::requestKey);
} }
public static void processRequest(Request req, Response res) throws IOException { public static void processRequest(Context context) {
RequestJson request = req.body(RequestJson.class); RequestJson request = context.bodyAsClass(RequestJson.class);
res.type("application/json");
String player = null; String player = null;
int uid = -1; int uid = -1;
@ -69,7 +62,7 @@ public final class RequestOnlyHttpHandler implements Router {
@Override @Override
public void timeout() { public void timeout() {
res.json(new ResponseJson("timeout", 500)); context.json(new ResponseJson("timeout", 500));
} }
}; };
try{ try{
@ -80,47 +73,46 @@ public final class RequestOnlyHttpHandler implements Router {
p.data = request.payload; p.data = request.payload;
SocketServer.sendUidPacket(uid, p, wait); SocketServer.sendUidPacket(uid, p, wait);
} catch (Exception e) { } catch (Exception e) {
res.json(new ResponseJson("error", 500, e.getStackTrace().toString())); context.json(new ResponseJson("error", 500, e.getStackTrace().toString()));
break; break;
} }
case "ping": case "ping":
// res.json(new ResponseJson("success", 200)); // res.json(new ResponseJson("success", 200));
if (wait == null) { if (wait == null) {
res.json(new ResponseJson("success", 200, null)); context.json(new ResponseJson("success", 200, null));
} else { } else {
var data = wait.getData(); var data = wait.getData();
if (data == null) { if (data == null) {
res.json(new ResponseJson("timeout", 500)); context.json(new ResponseJson("timeout", 500));
} else { } else {
res.json(new ResponseJson(data.message, data.code, data.data)); context.json(new ResponseJson(data.message, data.code, data.data));
} }
} }
break; break;
default: default:
res.json(new ResponseJson("400 Bad Request", 400)); context.json(new ResponseJson("400 Bad Request", 400));
break; break;
} }
return; return;
} }
res.json(new ResponseJson("403 Forbidden", 403)); context.json(new ResponseJson("403 Forbidden", 403));
} }
public static void requestKey(Request req, Response res) throws IOException { public static void requestKey(Context context) {
RequestAuth request = req.body(RequestAuth.class); RequestAuth request = context.bodyAsClass(RequestAuth.class);
if (request.otp != null && !request.otp.equals("")) { if (request.otp != null && !request.otp.equals("")) {
if (PluginCommand.getInstance().tickets.get(request.otp) == null) { if (PluginCommand.getInstance().tickets.get(request.otp) == null) {
res.json(new ResponseAuth(404, "Not found", null)); context.json(new ResponseAuth(404, "Not found", null));
return; return;
} }
String key = SocketData.tickets.get(request.otp).key; String key = SocketData.tickets.get(request.otp).key;
if (key == null){ if (key == null){
res.json(new ResponseAuth(403, "Not ready yet", null)); context.json(new ResponseAuth(403, "Not ready yet", null));
} else { } else {
SocketData.tickets.remove(request.otp); SocketData.tickets.remove(request.otp);
res.json(new ResponseAuth(200, "", key)); context.json(new ResponseAuth(200, "", key));
} }
return;
} else if (request.uid != 0) { } else if (request.uid != 0) {
String otp = new DecimalFormat("000000").format(new Random().nextInt(999999)); String otp = new DecimalFormat("000000").format(new Random().nextInt(999999));
while (PluginCommand.getInstance().tickets.containsKey(otp)){ while (PluginCommand.getInstance().tickets.containsKey(otp)){
@ -128,17 +120,16 @@ public final class RequestOnlyHttpHandler implements Router {
} }
String targetPlayer = SocketData.getPlayer(request.uid); String targetPlayer = SocketData.getPlayer(request.uid);
if (targetPlayer == null){ if (targetPlayer == null){
res.json(new ResponseAuth(404, "Not found", null)); context.json(new ResponseAuth(404, "Not found", null));
return; return;
} }
var otpPacket = new OtpPacket(request.uid, otp, System.currentTimeMillis() / 1000 + 300, true); var otpPacket = new OtpPacket(request.uid, otp, System.currentTimeMillis() / 1000 + 300, true);
if (!SocketServer.sendPacket(SocketData.getPlayerInServer(request.uid), otpPacket)) { if (!SocketServer.sendPacket(SocketData.getPlayerInServer(request.uid), otpPacket)) {
res.json(new ResponseAuth(500, "Send otp to server failed.", null)); context.json(new ResponseAuth(500, "Send otp to server failed.", null));
return; return;
} }
SocketData.tickets.put(otp, otpPacket); SocketData.tickets.put(otp, otpPacket);
res.json(new ResponseAuth(201, "Code generated", otp)); context.json(new ResponseAuth(201, "Code generated", otp));
return;
} }
} }
} }

View File

@ -19,6 +19,8 @@ import java.util.ArrayList;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import static com.mojo.consoleplus.ConsolePlus.gson;
// Socket 客户端 // Socket 客户端
public class SocketClient { public class SocketClient {
public static ClientThread clientThread; public static ClientThread clientThread;
@ -129,11 +131,11 @@ public class SocketClient {
try { try {
if (exit) return; if (exit) return;
String data = SocketUtils.readString(is); String data = SocketUtils.readString(is);
Packet packet = Grasscutter.getGsonFactory().fromJson(data, Packet.class); Packet packet = gson.fromJson(data, Packet.class);
switch (packet.type) { switch (packet.type) {
// 玩家类 // 玩家类
case Player: case Player:
var player = Grasscutter.getGsonFactory().fromJson(packet.data, Player.class); var player = gson.fromJson(packet.data, Player.class);
switch (player.type) { switch (player.type) {
// 运行命令 // 运行命令
case RunCommand -> { case RunCommand -> {
@ -170,10 +172,10 @@ public class SocketClient {
} }
break; break;
case OtpPacket: case OtpPacket:
var otpPacket = Grasscutter.getGsonFactory().fromJson(packet.data, OtpPacket.class); var otpPacket = gson.fromJson(packet.data, OtpPacket.class);
PluginCommand.getInstance().tickets.put(otpPacket.otp, new PluginCommand.Ticket(Grasscutter.getGameServer().getPlayerByUid(otpPacket.uid), otpPacket.expire, otpPacket.api)); PluginCommand.getInstance().tickets.put(otpPacket.otp, new PluginCommand.Ticket(Grasscutter.getGameServer().getPlayerByUid(otpPacket.uid), otpPacket.expire, otpPacket.api));
case Signature: case Signature:
var signaturePacket = Grasscutter.getGsonFactory().fromJson(packet.data, SignaturePacket.class); var signaturePacket = gson.fromJson(packet.data, SignaturePacket.class);
ConsolePlus.authHandler.setSignature(signaturePacket.signature); ConsolePlus.authHandler.setSignature(signaturePacket.signature);
break; break;
} }

View File

@ -15,6 +15,8 @@ import java.util.HashMap;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import static com.mojo.consoleplus.ConsolePlus.gson;
// Socket 服务器 // Socket 服务器
public class SocketServer { public class SocketServer {
// 客户端超时时间 // 客户端超时时间
@ -149,9 +151,9 @@ public class SocketServer {
while (true) { while (true) {
try { try {
String data = SocketUtils.readString(is); String data = SocketUtils.readString(is);
Packet packet = Grasscutter.getGsonFactory().fromJson(data, Packet.class); Packet packet = gson.fromJson(data, Packet.class);
if (packet.type == PacketEnum.AuthPacket) { if (packet.type == PacketEnum.AuthPacket) {
AuthPacket authPacket = Grasscutter.getGsonFactory().fromJson(packet.data, AuthPacket.class); AuthPacket authPacket = gson.fromJson(packet.data, AuthPacket.class);
if (authPacket.token.equals(token)) { if (authPacket.token.equals(token)) {
mLogger.info("[Mojo Console] Client {} auth success.", address); mLogger.info("[Mojo Console] Client {} auth success.", address);
auth = true; auth = true;
@ -172,12 +174,12 @@ public class SocketServer {
switch (packet.type) { switch (packet.type) {
// 缓存玩家列表 // 缓存玩家列表
case PlayerList -> { case PlayerList -> {
PlayerList playerList = Grasscutter.getGsonFactory().fromJson(packet.data, PlayerList.class); PlayerList playerList = gson.fromJson(packet.data, PlayerList.class);
SocketData.playerList.put(address, playerList); SocketData.playerList.put(address, playerList);
} }
// Http信息返回 // Http信息返回
case HttpPacket -> { case HttpPacket -> {
HttpPacket httpPacket = Grasscutter.getGsonFactory().fromJson(packet.data, HttpPacket.class); HttpPacket httpPacket = gson.fromJson(packet.data, HttpPacket.class);
var socketWait = socketDataWaitList.get(packet.packetID); var socketWait = socketDataWaitList.get(packet.packetID);
if (socketWait == null) { if (socketWait == null) {
mLogger.error("[Mojo Console] HttpPacket: {} not found", packet.packetID); mLogger.error("[Mojo Console] HttpPacket: {} not found", packet.packetID);
@ -187,7 +189,7 @@ public class SocketServer {
socketDataWaitList.remove(packet.packetID); socketDataWaitList.remove(packet.packetID);
} }
case OtpPacket -> { case OtpPacket -> {
OtpPacket otpPacket = Grasscutter.getGsonFactory().fromJson(packet.data, OtpPacket.class); OtpPacket otpPacket = gson.fromJson(packet.data, OtpPacket.class);
if (otpPacket.remove) { if (otpPacket.remove) {
SocketData.tickets.remove(otpPacket.otp); SocketData.tickets.remove(otpPacket.otp);
} else { } else {

View File

@ -1,6 +1,8 @@
package com.mojo.consoleplus.socket.packet; package com.mojo.consoleplus.socket.packet;
import emu.grasscutter.Grasscutter; import com.google.gson.GsonBuilder;
import static com.mojo.consoleplus.ConsolePlus.gson;
public class AuthPacket extends BasePacket { public class AuthPacket extends BasePacket {
public String token; public String token;
@ -11,7 +13,7 @@ public class AuthPacket extends BasePacket {
@Override @Override
public String getPacket() { public String getPacket() {
return Grasscutter.getGsonFactory().toJson(this); return gson.toJson(this);
} }
@Override @Override

View File

@ -5,6 +5,8 @@ import com.mojo.consoleplus.socket.packet.BasePacket;
import com.mojo.consoleplus.socket.packet.PacketEnum; import com.mojo.consoleplus.socket.packet.PacketEnum;
import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter;
import static com.mojo.consoleplus.ConsolePlus.gson;
// 玩家操作类 // 玩家操作类
public class Player extends BasePacket { public class Player extends BasePacket {
public PlayerEnum type; public PlayerEnum type;
@ -13,7 +15,7 @@ public class Player extends BasePacket {
@Override @Override
public String getPacket() { public String getPacket() {
return Grasscutter.getGsonFactory().toJson(this); return gson.toJson(this);
} }
@Override @Override