mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-22 03:45:10 +01:00
Run IntelliJ IDEA code formatter
This commit is contained in:
@@ -4,9 +4,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.core.util.JavalinLogger;
|
||||
import io.javalin.http.ContentType;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
@@ -53,13 +51,14 @@ public final class HttpServer {
|
||||
|
||||
/**
|
||||
* Creates an HTTP(S) server.
|
||||
*
|
||||
* @return A server instance.
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
private static Server createServer() {
|
||||
Server server = new Server();
|
||||
ServerConnector serverConnector
|
||||
= new ServerConnector(server);
|
||||
= new ServerConnector(server);
|
||||
|
||||
if (HTTP_ENCRYPTION.useEncryption) {
|
||||
var sslContextFactory = new SslContextFactory.Server();
|
||||
@@ -97,6 +96,7 @@ public final class HttpServer {
|
||||
|
||||
/**
|
||||
* Returns the handle for the Express application.
|
||||
*
|
||||
* @return A Javalin instance.
|
||||
*/
|
||||
public Javalin getHandle() {
|
||||
@@ -105,6 +105,7 @@ public final class HttpServer {
|
||||
|
||||
/**
|
||||
* Initializes the provided class.
|
||||
*
|
||||
* @param router The router class.
|
||||
* @return Method chaining.
|
||||
*/
|
||||
@@ -121,18 +122,20 @@ public final class HttpServer {
|
||||
routerInstance.applyRoutes(this.javalin); // Apply routes.
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().warn(translate("messages.dispatch.router_error"), exception);
|
||||
} return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts listening on the HTTP server.
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
public void start() throws UnsupportedEncodingException {
|
||||
// Attempt to start the HTTP server.
|
||||
if (HTTP_INFO.bindAddress.equals("")) {
|
||||
this.javalin.start(HTTP_INFO.bindPort);
|
||||
}else {
|
||||
} else {
|
||||
this.javalin.start(HTTP_INFO.bindAddress, HTTP_INFO.bindPort);
|
||||
}
|
||||
|
||||
@@ -144,21 +147,22 @@ public final class HttpServer {
|
||||
* Handles the '/' (index) endpoint on the Express application.
|
||||
*/
|
||||
public static class DefaultRequestRouter implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
javalin.get("/", ctx -> {
|
||||
// Send file
|
||||
File file = new File(HTTP_STATIC_FILES.indexFile);
|
||||
if (!file.exists()) {
|
||||
ctx.contentType(ContentType.TEXT_HTML);
|
||||
ctx.result("""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<body>%s</body>
|
||||
</html>
|
||||
""".formatted(translate("messages.status.welcome")));
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<body>%s</body>
|
||||
</html>
|
||||
""".formatted(translate("messages.status.welcome")));
|
||||
} else {
|
||||
var filePath = file.getPath();
|
||||
ContentType fromExtension = ContentType.getContentTypeByExtension(filePath.substring(filePath.lastIndexOf(".") + 1));
|
||||
@@ -173,7 +177,8 @@ public final class HttpServer {
|
||||
* Handles unhandled endpoints on the Express application.
|
||||
*/
|
||||
public static class UnhandledRequestRouter implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
javalin.error(404, ctx -> {
|
||||
// Error log
|
||||
if (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING)
|
||||
@@ -183,17 +188,17 @@ public final class HttpServer {
|
||||
if (!file.exists()) {
|
||||
ctx.contentType(ContentType.TEXT_HTML);
|
||||
ctx.result("""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<img src="https://http.cat/404" />
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
<body>
|
||||
<img src="https://http.cat/404" />
|
||||
</body>
|
||||
</html>
|
||||
""");
|
||||
} else {
|
||||
var filePath = file.getPath();
|
||||
ContentType fromExtension = ContentType.getContentTypeByExtension(filePath.substring(filePath.lastIndexOf(".") + 1));
|
||||
|
||||
@@ -10,18 +10,20 @@ public interface Router {
|
||||
|
||||
/**
|
||||
* Called when the router is initialized by Express.
|
||||
*
|
||||
* @param javalin A Javalin instance.
|
||||
*/
|
||||
void applyRoutes(Javalin javalin);
|
||||
|
||||
/**
|
||||
* Applies this handler to all endpoint types
|
||||
*
|
||||
* @param javalin A Javalin instance.
|
||||
* @param path
|
||||
* @param ctx
|
||||
* @return The Javalin instance.
|
||||
*/
|
||||
public default Javalin allRoutes(Javalin javalin, String path, Handler ctx) {
|
||||
default Javalin allRoutes(Javalin javalin, String path, Handler ctx) {
|
||||
javalin.get(path, ctx);
|
||||
javalin.post(path, ctx);
|
||||
javalin.put(path, ctx);
|
||||
|
||||
@@ -4,8 +4,10 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.auth.AuthenticationSystem;
|
||||
import emu.grasscutter.auth.OAuthAuthenticator.ClientType;
|
||||
import emu.grasscutter.server.http.Router;
|
||||
import emu.grasscutter.server.http.objects.*;
|
||||
import emu.grasscutter.server.http.objects.ComboTokenReqJson;
|
||||
import emu.grasscutter.server.http.objects.ComboTokenReqJson.LoginTokenData;
|
||||
import emu.grasscutter.server.http.objects.LoginAccountRequestJson;
|
||||
import emu.grasscutter.server.http.objects.LoginTokenRequestJson;
|
||||
import emu.grasscutter.utils.JsonUtils;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
@@ -16,43 +18,6 @@ import static emu.grasscutter.utils.Language.translate;
|
||||
* Handles requests related to authentication. (aka dispatch)
|
||||
*/
|
||||
public final class DispatchHandler implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
// OS
|
||||
// Username & Password login (from client).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/login", DispatchHandler::clientLogin);
|
||||
// Cached token login (from registry).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/verify", DispatchHandler::tokenLogin);
|
||||
// Combo token login (from session key).
|
||||
javalin.post("/hk4e_global/combo/granter/login/v2/login", DispatchHandler::sessionKeyLogin);
|
||||
|
||||
// CN
|
||||
// Username & Password login (from client).
|
||||
javalin.post("/hk4e_cn/mdk/shield/api/login", DispatchHandler::clientLogin);
|
||||
// Cached token login (from registry).
|
||||
javalin.post("/hk4e_cn/mdk/shield/api/verify", DispatchHandler::tokenLogin);
|
||||
// Combo token login (from session key).
|
||||
javalin.post("/hk4e_cn/combo/granter/login/v2/login", DispatchHandler::sessionKeyLogin);
|
||||
|
||||
// External login (from other clients).
|
||||
javalin.get("/authentication/type", ctx -> ctx.result(Grasscutter.getAuthenticationSystem().getClass().getSimpleName()));
|
||||
javalin.post("/authentication/login", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handleLogin(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.post("/authentication/register", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handleAccountCreation(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.post("/authentication/change_password", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handlePasswordReset(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
|
||||
// External login (from OAuth2).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/loginByThirdparty", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleLogin(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.get("/authentication/openid/redirect", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleTokenProcess(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.get("/Api/twitter_login", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleRedirection(AuthenticationSystem.fromExternalRequest(ctx), ClientType.DESKTOP));
|
||||
javalin.get("/sdkTwitterLogin.html", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleRedirection(AuthenticationSystem.fromExternalRequest(ctx), ClientType.MOBILE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /hk4e_global/mdk/shield/api/login
|
||||
*/
|
||||
@@ -67,8 +32,8 @@ public final class DispatchHandler implements Router {
|
||||
|
||||
// Pass data to authentication handler.
|
||||
var responseData = Grasscutter.getAuthenticationSystem()
|
||||
.getPasswordAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromPasswordRequest(ctx, bodyData));
|
||||
.getPasswordAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromPasswordRequest(ctx, bodyData));
|
||||
// Send response.
|
||||
ctx.json(responseData);
|
||||
|
||||
@@ -90,8 +55,8 @@ public final class DispatchHandler implements Router {
|
||||
|
||||
// Pass data to authentication handler.
|
||||
var responseData = Grasscutter.getAuthenticationSystem()
|
||||
.getTokenAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromTokenRequest(ctx, bodyData));
|
||||
.getTokenAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromTokenRequest(ctx, bodyData));
|
||||
// Send response.
|
||||
ctx.json(responseData);
|
||||
|
||||
@@ -116,12 +81,50 @@ public final class DispatchHandler implements Router {
|
||||
|
||||
// Pass data to authentication handler.
|
||||
var responseData = Grasscutter.getAuthenticationSystem()
|
||||
.getSessionKeyAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromComboTokenRequest(ctx, bodyData, tokenData));
|
||||
.getSessionKeyAuthenticator()
|
||||
.authenticate(AuthenticationSystem.fromComboTokenRequest(ctx, bodyData, tokenData));
|
||||
// Send response.
|
||||
ctx.json(responseData);
|
||||
|
||||
// Log to console.
|
||||
Grasscutter.getLogger().info(translate("messages.dispatch.account.login_attempt", ctx.ip()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
// OS
|
||||
// Username & Password login (from client).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/login", DispatchHandler::clientLogin);
|
||||
// Cached token login (from registry).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/verify", DispatchHandler::tokenLogin);
|
||||
// Combo token login (from session key).
|
||||
javalin.post("/hk4e_global/combo/granter/login/v2/login", DispatchHandler::sessionKeyLogin);
|
||||
|
||||
// CN
|
||||
// Username & Password login (from client).
|
||||
javalin.post("/hk4e_cn/mdk/shield/api/login", DispatchHandler::clientLogin);
|
||||
// Cached token login (from registry).
|
||||
javalin.post("/hk4e_cn/mdk/shield/api/verify", DispatchHandler::tokenLogin);
|
||||
// Combo token login (from session key).
|
||||
javalin.post("/hk4e_cn/combo/granter/login/v2/login", DispatchHandler::sessionKeyLogin);
|
||||
|
||||
// External login (from other clients).
|
||||
javalin.get("/authentication/type", ctx -> ctx.result(Grasscutter.getAuthenticationSystem().getClass().getSimpleName()));
|
||||
javalin.post("/authentication/login", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handleLogin(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.post("/authentication/register", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handleAccountCreation(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.post("/authentication/change_password", ctx -> Grasscutter.getAuthenticationSystem().getExternalAuthenticator()
|
||||
.handlePasswordReset(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
|
||||
// External login (from OAuth2).
|
||||
javalin.post("/hk4e_global/mdk/shield/api/loginByThirdparty", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleLogin(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.get("/authentication/openid/redirect", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleTokenProcess(AuthenticationSystem.fromExternalRequest(ctx)));
|
||||
javalin.get("/Api/twitter_login", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleRedirection(AuthenticationSystem.fromExternalRequest(ctx), ClientType.DESKTOP));
|
||||
javalin.get("/sdkTwitterLogin.html", ctx -> Grasscutter.getAuthenticationSystem().getOAuthAuthenticator()
|
||||
.handleRedirection(AuthenticationSystem.fromExternalRequest(ctx), ClientType.MOBILE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ package emu.grasscutter.server.http.dispatch;
|
||||
import com.google.protobuf.ByteString;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp;
|
||||
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
||||
import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo;
|
||||
import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp;
|
||||
import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo;
|
||||
import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo;
|
||||
import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent;
|
||||
import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent;
|
||||
import emu.grasscutter.server.http.Router;
|
||||
@@ -15,18 +15,19 @@ import emu.grasscutter.utils.Crypto;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.security.Signature;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
/**
|
||||
* Handles requests related to region queries.
|
||||
@@ -44,86 +45,6 @@ public final class RegionHandler implements Router {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures region data according to configuration.
|
||||
*/
|
||||
private void initialize() {
|
||||
String dispatchDomain = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
||||
|
||||
// Create regions.
|
||||
List<RegionSimpleInfo> servers = new ArrayList<>();
|
||||
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts.
|
||||
|
||||
var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions));
|
||||
if (SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) {
|
||||
Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
||||
System.exit(1);
|
||||
} else if (configuredRegions.size() == 0)
|
||||
configuredRegions.add(new Region("os_usa", DISPATCH_INFO.defaultName,
|
||||
lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress),
|
||||
lr(GAME_INFO.accessPort, GAME_INFO.bindPort)));
|
||||
|
||||
configuredRegions.forEach(region -> {
|
||||
if (usedNames.contains(region.Name)) {
|
||||
Grasscutter.getLogger().error("Region name already in use.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a region identifier.
|
||||
var identifier = RegionSimpleInfo.newBuilder()
|
||||
.setName(region.Name).setTitle(region.Title).setType("DEV_PUBLIC")
|
||||
.setDispatchUrl(dispatchDomain + "/query_cur_region/" + region.Name)
|
||||
.build();
|
||||
usedNames.add(region.Name); servers.add(identifier);
|
||||
|
||||
// Create a region info object.
|
||||
var regionInfo = RegionInfo.newBuilder()
|
||||
.setGateserverIp(region.Ip).setGateserverPort(region.Port)
|
||||
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.build();
|
||||
// Create an updated region query.
|
||||
var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build();
|
||||
regions.put(region.Name, new RegionData(updatedQuery, Utils.base64Encode(updatedQuery.toByteString().toByteArray())));
|
||||
});
|
||||
|
||||
// Create a config object.
|
||||
byte[] customConfig = "{\"sdkenv\":\"2\",\"checkdevice\":\"false\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
||||
Crypto.xor(customConfig, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||
|
||||
// Create an updated region list.
|
||||
QueryRegionListHttpRsp updatedRegionList = QueryRegionListHttpRsp.newBuilder()
|
||||
.addAllRegionList(servers)
|
||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfig))
|
||||
.setEnableLoginPc(true).build();
|
||||
|
||||
// Set the region list response.
|
||||
regionListResponse = Utils.base64Encode(updatedRegionList.toByteString().toByteArray());
|
||||
|
||||
// CN
|
||||
// Create a config object.
|
||||
byte[] customConfigcn = "{\"sdkenv\":\"0\",\"checkdevice\":\"true\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
||||
Crypto.xor(customConfigcn, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||
|
||||
// Create an updated region list.
|
||||
QueryRegionListHttpRsp updatedRegionListcn = QueryRegionListHttpRsp.newBuilder()
|
||||
.addAllRegionList(servers)
|
||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfigcn))
|
||||
.setEnableLoginPc(true).build();
|
||||
|
||||
// Set the region list response.
|
||||
regionListResponsecn = Utils.base64Encode(updatedRegionListcn.toByteString().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
javalin.get("/query_region_list", RegionHandler::queryRegionList);
|
||||
javalin.get("/query_cur_region/{region}", RegionHandler::queryCurrentRegion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle query region list request.
|
||||
*
|
||||
@@ -140,7 +61,7 @@ public final class RegionHandler implements Router {
|
||||
|
||||
// Determine the region list to use based on the version and platform.
|
||||
if ("CNRELiOS".equals(versionCode) || "CNRELWin".equals(versionCode)
|
||||
|| "CNRELAndroid".equals(versionCode)) {
|
||||
|| "CNRELAndroid".equals(versionCode)) {
|
||||
// Use the CN region list.
|
||||
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponsecn);
|
||||
event.call();
|
||||
@@ -149,7 +70,7 @@ public final class RegionHandler implements Router {
|
||||
// Respond with the event result.
|
||||
ctx.result(event.getRegionList());
|
||||
} else if ("OSRELiOS".equals(versionCode) || "OSRELWin".equals(versionCode)
|
||||
|| "OSRELAndroid".equals(versionCode)) {
|
||||
|| "OSRELAndroid".equals(versionCode)) {
|
||||
// Use the OS region list.
|
||||
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponse);
|
||||
event.call();
|
||||
@@ -205,11 +126,12 @@ public final class RegionHandler implements Router {
|
||||
String[] versionCode = versionName.replaceAll(Pattern.compile("[a-zA-Z]").pattern(), "").split("\\.");
|
||||
int versionMajor = Integer.parseInt(versionCode[0]);
|
||||
int versionMinor = Integer.parseInt(versionCode[1]);
|
||||
int versionFix = Integer.parseInt(versionCode[2]);
|
||||
int versionFix = Integer.parseInt(versionCode[2]);
|
||||
|
||||
if (versionMajor >= 3 || (versionMajor == 2 && versionMinor == 7 && versionFix >= 50) || (versionMajor == 2 && versionMinor == 8)) {
|
||||
try {
|
||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call();
|
||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData);
|
||||
event.call();
|
||||
|
||||
if (ctx.queryParam("dispatchSeed") == null) {
|
||||
// More love for UA Patch players
|
||||
@@ -255,14 +177,13 @@ public final class RegionHandler implements Router {
|
||||
rsp.sign = Utils.base64Encode(privateSignature.sign());
|
||||
|
||||
ctx.json(rsp);
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("An error occurred while handling query_cur_region.", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Invoke event.
|
||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call();
|
||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData);
|
||||
event.call();
|
||||
// Respond with event result.
|
||||
ctx.result(event.getRegionInfo());
|
||||
}
|
||||
@@ -270,6 +191,96 @@ public final class RegionHandler implements Router {
|
||||
Grasscutter.getLogger().info(String.format("Client %s request: query_cur_region/%s", ctx.ip(), regionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current region query.
|
||||
*
|
||||
* @return A {@link QueryCurrRegionHttpRsp} object.
|
||||
*/
|
||||
public static QueryCurrRegionHttpRsp getCurrentRegion() {
|
||||
return SERVER.runMode == ServerRunMode.HYBRID ? regions.get("os_usa").getRegionQuery() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures region data according to configuration.
|
||||
*/
|
||||
private void initialize() {
|
||||
String dispatchDomain = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
||||
|
||||
// Create regions.
|
||||
List<RegionSimpleInfo> servers = new ArrayList<>();
|
||||
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts.
|
||||
|
||||
var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions));
|
||||
if (SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) {
|
||||
Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
||||
System.exit(1);
|
||||
} else if (configuredRegions.size() == 0)
|
||||
configuredRegions.add(new Region("os_usa", DISPATCH_INFO.defaultName,
|
||||
lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress),
|
||||
lr(GAME_INFO.accessPort, GAME_INFO.bindPort)));
|
||||
|
||||
configuredRegions.forEach(region -> {
|
||||
if (usedNames.contains(region.Name)) {
|
||||
Grasscutter.getLogger().error("Region name already in use.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a region identifier.
|
||||
var identifier = RegionSimpleInfo.newBuilder()
|
||||
.setName(region.Name).setTitle(region.Title).setType("DEV_PUBLIC")
|
||||
.setDispatchUrl(dispatchDomain + "/query_cur_region/" + region.Name)
|
||||
.build();
|
||||
usedNames.add(region.Name);
|
||||
servers.add(identifier);
|
||||
|
||||
// Create a region info object.
|
||||
var regionInfo = RegionInfo.newBuilder()
|
||||
.setGateserverIp(region.Ip).setGateserverPort(region.Port)
|
||||
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.build();
|
||||
// Create an updated region query.
|
||||
var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build();
|
||||
regions.put(region.Name, new RegionData(updatedQuery, Utils.base64Encode(updatedQuery.toByteString().toByteArray())));
|
||||
});
|
||||
|
||||
// Create a config object.
|
||||
byte[] customConfig = "{\"sdkenv\":\"2\",\"checkdevice\":\"false\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
||||
Crypto.xor(customConfig, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||
|
||||
// Create an updated region list.
|
||||
QueryRegionListHttpRsp updatedRegionList = QueryRegionListHttpRsp.newBuilder()
|
||||
.addAllRegionList(servers)
|
||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfig))
|
||||
.setEnableLoginPc(true).build();
|
||||
|
||||
// Set the region list response.
|
||||
regionListResponse = Utils.base64Encode(updatedRegionList.toByteString().toByteArray());
|
||||
|
||||
// CN
|
||||
// Create a config object.
|
||||
byte[] customConfigcn = "{\"sdkenv\":\"0\",\"checkdevice\":\"true\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
||||
Crypto.xor(customConfigcn, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||
|
||||
// Create an updated region list.
|
||||
QueryRegionListHttpRsp updatedRegionListcn = QueryRegionListHttpRsp.newBuilder()
|
||||
.addAllRegionList(servers)
|
||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfigcn))
|
||||
.setEnableLoginPc(true).build();
|
||||
|
||||
// Set the region list response.
|
||||
regionListResponsecn = Utils.base64Encode(updatedRegionListcn.toByteString().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
javalin.get("/query_region_list", RegionHandler::queryRegionList);
|
||||
javalin.get("/query_cur_region/{region}", RegionHandler::queryCurrentRegion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Region data container.
|
||||
*/
|
||||
@@ -290,12 +301,4 @@ public final class RegionHandler implements Router {
|
||||
return this.base64;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current region query.
|
||||
* @return A {@link QueryCurrRegionHttpRsp} object.
|
||||
*/
|
||||
public static QueryCurrRegionHttpRsp getCurrentRegion() {
|
||||
return SERVER.runMode == ServerRunMode.HYBRID ? regions.get("os_usa").getRegionQuery() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package emu.grasscutter.server.http.documentation;
|
||||
|
||||
import emu.grasscutter.server.http.Router;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
public final class DocumentationServerHandler implements Router {
|
||||
|
||||
|
||||
@@ -5,12 +5,12 @@ import emu.grasscutter.utils.Language;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE;
|
||||
|
||||
final class GachaMappingRequestHandler implements DocumentationHandler {
|
||||
private List<String> gachaJsons;
|
||||
private final List<String> gachaJsons;
|
||||
|
||||
GachaMappingRequestHandler() {
|
||||
this.gachaJsons = Tools.createGachaMappingJsons();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package emu.grasscutter.server.http.documentation;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.data.GameData;
|
||||
@@ -14,6 +12,7 @@ import emu.grasscutter.utils.Language;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
@@ -42,7 +41,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
Matcher matcher = localePattern.matcher(acceptLanguage);
|
||||
if (matcher.find()) {
|
||||
String lang = matcher.group(0);
|
||||
langIdx = Language.TextStrings.MAP_GC_LANGUAGES.getOrDefault(lang,0);
|
||||
langIdx = Language.TextStrings.MAP_GC_LANGUAGES.getOrDefault(lang, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +61,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
final List<Language> languages = Language.TextStrings.getLanguages();
|
||||
final List<StringBuilder> sbs = new ArrayList<>(NUM_LANGUAGES);
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.add(new StringBuilder(""));
|
||||
sbs.add(new StringBuilder());
|
||||
|
||||
// Commands table
|
||||
CommandMap.getInstance().getHandlersAsList().forEach(cmd -> {
|
||||
@@ -71,7 +70,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.get(langIdx).append("<tr><td><code>" + label + "</code></td><td>" + languages.get(langIdx).get(descKey) + "</td></tr>\n");
|
||||
});
|
||||
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||
sbs.forEach(sb -> sb.setLength(sb.length() - 1)); // Remove trailing \n
|
||||
final List<String> cmdsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||
|
||||
// Avatars table
|
||||
@@ -83,7 +82,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||
});
|
||||
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||
sbs.forEach(sb -> sb.setLength(sb.length() - 1)); // Remove trailing \n
|
||||
final List<String> avatarsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||
|
||||
// Items table
|
||||
@@ -95,7 +94,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||
});
|
||||
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||
sbs.forEach(sb -> sb.setLength(sb.length() - 1)); // Remove trailing \n
|
||||
final List<String> itemsTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||
|
||||
// Scenes table
|
||||
@@ -105,7 +104,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + data.getScriptData() + "</td></tr>\n");
|
||||
});
|
||||
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||
sbs.forEach(sb -> sb.setLength(sb.length() - 1)); // Remove trailing \n
|
||||
final List<String> scenesTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||
|
||||
// Monsters table
|
||||
@@ -116,7 +115,7 @@ final class HandbookRequestHandler implements DocumentationHandler {
|
||||
for (int langIdx = 0; langIdx < NUM_LANGUAGES; langIdx++)
|
||||
sbs.get(langIdx).append("<tr><td><code>" + id + "</code></td><td>" + name.get(langIdx) + "</td></tr>\n");
|
||||
});
|
||||
sbs.forEach(sb -> sb.setLength(sb.length()-1)); // Remove trailing \n
|
||||
sbs.forEach(sb -> sb.setLength(sb.length() - 1)); // Remove trailing \n
|
||||
final List<String> monstersTable = sbs.stream().map(StringBuilder::toString).toList();
|
||||
|
||||
// Add translated title etc. to the page.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package emu.grasscutter.server.http.documentation;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import io.javalin.http.ContentType;
|
||||
@@ -10,6 +8,8 @@ import io.javalin.http.Context;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
final class RootRequestHandler implements DocumentationHandler {
|
||||
|
||||
private final String template;
|
||||
@@ -33,8 +33,8 @@ final class RootRequestHandler implements DocumentationHandler {
|
||||
}
|
||||
|
||||
String content = template.replace("{{TITLE}}", translate("documentation.index.title"))
|
||||
.replace("{{ITEM_HANDBOOK}}", translate("documentation.index.handbook"))
|
||||
.replace("{{ITEM_GACHA_MAPPING}}", translate("documentation.index.gacha_mapping"));
|
||||
.replace("{{ITEM_HANDBOOK}}", translate("documentation.index.handbook"))
|
||||
.replace("{{ITEM_GACHA_MAPPING}}", translate("documentation.index.gacha_mapping"));
|
||||
ctx.contentType(ContentType.TEXT_HTML);
|
||||
ctx.result(content);
|
||||
}
|
||||
|
||||
@@ -2,39 +2,24 @@ package emu.grasscutter.server.http.handlers;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
||||
import emu.grasscutter.server.http.Router;
|
||||
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
|
||||
/**
|
||||
* Handles requests related to the announcements page.
|
||||
*/
|
||||
public final class AnnouncementsHandler implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin, "/common/hk4e_global/announcement/api/getAlertPic", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"total\":0,\"list\":[]}}"));
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin,"/common/hk4e_global/announcement/api/getAlertAnn", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"alert\":false,\"alert_id\":0,\"remind\":true}}"));
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin,"/common/hk4e_global/announcement/api/getAnnList", AnnouncementsHandler::getAnnouncement);
|
||||
// hk4e-api-os-static.hoyoverse.com
|
||||
this.allRoutes(javalin,"/common/hk4e_global/announcement/api/getAnnContent", AnnouncementsHandler::getAnnouncement);
|
||||
// hk4e-sdk-os.hoyoverse.com
|
||||
this.allRoutes(javalin,"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}"));
|
||||
|
||||
javalin.get("/hk4e/announcement/*", AnnouncementsHandler::getPageResources);
|
||||
}
|
||||
|
||||
private static void getAnnouncement(Context ctx) {
|
||||
String data = "";
|
||||
if (Objects.equals(ctx.endpointHandlerPath(), "/common/hk4e_global/announcement/api/getAnnContent")) {
|
||||
@@ -63,8 +48,8 @@ public final class AnnouncementsHandler implements Router {
|
||||
}
|
||||
|
||||
String dispatchDomain = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
|
||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
||||
|
||||
data = data
|
||||
.replace("{{DISPATCH_PUBLIC}}", dispatchDomain)
|
||||
@@ -94,4 +79,20 @@ public final class AnnouncementsHandler implements Router {
|
||||
ctx.status(404);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin, "/common/hk4e_global/announcement/api/getAlertPic", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"total\":0,\"list\":[]}}"));
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin, "/common/hk4e_global/announcement/api/getAlertAnn", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"alert\":false,\"alert_id\":0,\"remind\":true}}"));
|
||||
// hk4e-api-os.hoyoverse.com
|
||||
this.allRoutes(javalin, "/common/hk4e_global/announcement/api/getAnnList", AnnouncementsHandler::getAnnouncement);
|
||||
// hk4e-api-os-static.hoyoverse.com
|
||||
this.allRoutes(javalin, "/common/hk4e_global/announcement/api/getAnnContent", AnnouncementsHandler::getAnnouncement);
|
||||
// hk4e-sdk-os.hoyoverse.com
|
||||
this.allRoutes(javalin, "/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}"));
|
||||
|
||||
javalin.get("/hk4e/announcement/*", AnnouncementsHandler::getPageResources);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,17 +29,11 @@ import static emu.grasscutter.utils.Language.translate;
|
||||
* Handles all gacha-related HTTP requests.
|
||||
*/
|
||||
public final class GachaHandler implements Router {
|
||||
@Getter private static final Path gachaMappingsPath = FileUtils.getDataUserPath("gacha/mappings.js");
|
||||
@Getter
|
||||
private static final Path gachaMappingsPath = FileUtils.getDataUserPath("gacha/mappings.js");
|
||||
@Deprecated(forRemoval = true)
|
||||
public static final String gachaMappings = gachaMappingsPath.toString();
|
||||
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
javalin.get("/gacha", GachaHandler::gachaRecords);
|
||||
javalin.get("/gacha/details", GachaHandler::gachaDetails);
|
||||
|
||||
javalin._conf.addSinglePageRoot("/gacha/mappings", gachaMappingsPath.toString(), Location.EXTERNAL); // TODO: This ***must*** be changed to take the Path not a String. This might involve upgrading Javalin.
|
||||
}
|
||||
|
||||
private static void gachaRecords(Context ctx) {
|
||||
String sessionKey = ctx.queryParam("s");
|
||||
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
||||
@@ -98,10 +92,10 @@ public final class GachaHandler implements Router {
|
||||
|
||||
// Add translated title etc. to the page.
|
||||
template = template.replace("{{TITLE}}", translate(player, "gacha.details.title"))
|
||||
.replace("{{AVAILABLE_FIVE_STARS}}", translate(player, "gacha.details.available_five_stars"))
|
||||
.replace("{{AVAILABLE_FOUR_STARS}}", translate(player, "gacha.details.available_four_stars"))
|
||||
.replace("{{AVAILABLE_THREE_STARS}}", translate(player, "gacha.details.available_three_stars"))
|
||||
.replace("{{LANGUAGE}}", Utils.getLanguageCode(account.getLocale()));
|
||||
.replace("{{AVAILABLE_FIVE_STARS}}", translate(player, "gacha.details.available_five_stars"))
|
||||
.replace("{{AVAILABLE_FOUR_STARS}}", translate(player, "gacha.details.available_four_stars"))
|
||||
.replace("{{AVAILABLE_THREE_STARS}}", translate(player, "gacha.details.available_three_stars"))
|
||||
.replace("{{LANGUAGE}}", Utils.getLanguageCode(account.getLocale()));
|
||||
|
||||
// Get the banner info for the banner we want.
|
||||
int scheduleId = Integer.parseInt(ctx.queryParam("scheduleId"));
|
||||
@@ -135,4 +129,12 @@ public final class GachaHandler implements Router {
|
||||
ctx.contentType(ContentType.TEXT_HTML);
|
||||
ctx.result(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
javalin.get("/gacha", GachaHandler::gachaRecords);
|
||||
javalin.get("/gacha/details", GachaHandler::gachaDetails);
|
||||
|
||||
javalin._conf.addSinglePageRoot("/gacha/mappings", gachaMappingsPath.toString(), Location.EXTERNAL); // TODO: This ***must*** be changed to take the Path not a String. This might involve upgrading Javalin.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
package emu.grasscutter.server.http.handlers;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.ACCOUNT;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
||||
import emu.grasscutter.server.http.Router;
|
||||
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
||||
import emu.grasscutter.server.http.objects.WebStaticVersionResponse;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.ACCOUNT;
|
||||
|
||||
/**
|
||||
* Handles all generic, hard-coded responses.
|
||||
*/
|
||||
public final class GenericHandler implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
private static void serverStatus(Context ctx) {
|
||||
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||
int maxPlayer = ACCOUNT.maxPlayer;
|
||||
String version = GameConstants.VERSION;
|
||||
|
||||
ctx.result("{\"retcode\":0,\"status\":{\"playerCount\":" + playerCount + ",\"maxPlayer\":" + maxPlayer + ",\"version\":\"" + version + "\"}}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
// hk4e-sdk-os.hoyoverse.com
|
||||
javalin.get("/hk4e_global/mdk/agreement/api/getAgreementInfos", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"marketing_agreements\":[]}}"));
|
||||
// hk4e-sdk-os.hoyoverse.com (this could be either GET or POST based on the observation of different clients)
|
||||
@@ -45,12 +54,4 @@ public final class GenericHandler implements Router {
|
||||
|
||||
javalin.get("/status/server", GenericHandler::serverStatus);
|
||||
}
|
||||
|
||||
private static void serverStatus(Context ctx) {
|
||||
int playerCount = Grasscutter.getGameServer().getPlayers().size();
|
||||
int maxPlayer = ACCOUNT.maxPlayer;
|
||||
String version = GameConstants.VERSION;
|
||||
|
||||
ctx.result("{\"retcode\":0,\"status\":{\"playerCount\":" + playerCount + ",\"maxPlayer\":" + maxPlayer + ",\"version\":\"" + version + "\"}}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,16 @@ import io.javalin.http.Context;
|
||||
* Handles logging requests made to the server.
|
||||
*/
|
||||
public final class LogHandler implements Router {
|
||||
@Override public void applyRoutes(Javalin javalin) {
|
||||
private static void log(Context ctx) {
|
||||
// TODO: Figure out how to dump request body and log to file.
|
||||
ctx.result("{\"code\":0}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRoutes(Javalin javalin) {
|
||||
// overseauspider.yuanshen.com
|
||||
javalin.post("/log", LogHandler::log);
|
||||
// log-upload-os.mihoyo.com
|
||||
javalin.post("/crash/dataUpload", LogHandler::log);
|
||||
}
|
||||
|
||||
private static void log(Context ctx) {
|
||||
// TODO: Figure out how to dump request body and log to file.
|
||||
ctx.result("{\"code\":0}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
public class ComboTokenReqJson {
|
||||
public int app_id;
|
||||
public int channel_id;
|
||||
public String data;
|
||||
public String device;
|
||||
public String sign;
|
||||
|
||||
public static class LoginTokenData {
|
||||
public String uid;
|
||||
public String token;
|
||||
public boolean guest;
|
||||
}
|
||||
public int app_id;
|
||||
public int channel_id;
|
||||
public String data;
|
||||
public String device;
|
||||
public String sign;
|
||||
|
||||
public static class LoginTokenData {
|
||||
public String uid;
|
||||
public String token;
|
||||
public boolean guest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
public class ComboTokenResJson {
|
||||
public String message;
|
||||
public int retcode;
|
||||
public LoginData data = new LoginData();
|
||||
|
||||
public static class LoginData {
|
||||
public int account_type = 1;
|
||||
public boolean heartbeat;
|
||||
public String combo_id;
|
||||
public String combo_token;
|
||||
public String open_id;
|
||||
public String data = "{\"guest\":false}";
|
||||
public String fatigue_remind = null; // ?
|
||||
}
|
||||
public String message;
|
||||
public int retcode;
|
||||
public LoginData data = new LoginData();
|
||||
|
||||
public static class LoginData {
|
||||
public int account_type = 1;
|
||||
public boolean heartbeat;
|
||||
public String combo_id;
|
||||
public String combo_token;
|
||||
public String open_id;
|
||||
public String data = "{\"guest\":false}";
|
||||
public String fatigue_remind = null; // ?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.Handler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
public final class HttpJsonResponse implements Handler {
|
||||
private final String response;
|
||||
private final String[] missingRoutes = { // TODO: When http requests for theses routes are found please remove it from this list and update the route request type in the DispatchServer
|
||||
"/common/hk4e_global/announcement/api/getAlertPic",
|
||||
"/common/hk4e_global/announcement/api/getAlertAnn",
|
||||
"/common/hk4e_global/announcement/api/getAnnList",
|
||||
"/common/hk4e_global/announcement/api/getAnnContent",
|
||||
"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier",
|
||||
"/log/sdk/upload",
|
||||
"/sdk/upload",
|
||||
"/perf/config/verify",
|
||||
"/log",
|
||||
"/crash/dataUpload"
|
||||
"/common/hk4e_global/announcement/api/getAlertPic",
|
||||
"/common/hk4e_global/announcement/api/getAlertAnn",
|
||||
"/common/hk4e_global/announcement/api/getAnnList",
|
||||
"/common/hk4e_global/announcement/api/getAnnContent",
|
||||
"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier",
|
||||
"/log/sdk/upload",
|
||||
"/sdk/upload",
|
||||
"/perf/config/verify",
|
||||
"/log",
|
||||
"/crash/dataUpload"
|
||||
};
|
||||
|
||||
public HttpJsonResponse(String response) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
public class LoginAccountRequestJson {
|
||||
public String account;
|
||||
public String password;
|
||||
public boolean is_crypto;
|
||||
public String account;
|
||||
public String password;
|
||||
public boolean is_crypto;
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
public class LoginResultJson {
|
||||
public String message;
|
||||
public int retcode;
|
||||
public VerifyData data = new VerifyData();
|
||||
|
||||
public static class VerifyData {
|
||||
public VerifyAccountData account = new VerifyAccountData();
|
||||
public boolean device_grant_required = false;
|
||||
public String realname_operation = "NONE";
|
||||
public boolean realperson_required = false;
|
||||
public boolean safe_mobile_required = false;
|
||||
}
|
||||
|
||||
public static class VerifyAccountData {
|
||||
public String uid;
|
||||
public String name = "";
|
||||
public String email = "";
|
||||
public String mobile = "";
|
||||
public String is_email_verify = "0";
|
||||
public String realname = "";
|
||||
public String identity_card = "";
|
||||
public String token;
|
||||
public String safe_mobile = "";
|
||||
public String facebook_name = "";
|
||||
public String twitter_name = "";
|
||||
public String game_center_name = "";
|
||||
public String google_name = "";
|
||||
public String apple_name = "";
|
||||
public String sony_name = "";
|
||||
public String tap_name = "";
|
||||
public String country = "US";
|
||||
public String reactivate_ticket = "";
|
||||
public String area_code = "**";
|
||||
public String device_grant_ticket = "";
|
||||
}
|
||||
public String message;
|
||||
public int retcode;
|
||||
public VerifyData data = new VerifyData();
|
||||
|
||||
public static class VerifyData {
|
||||
public VerifyAccountData account = new VerifyAccountData();
|
||||
public boolean device_grant_required = false;
|
||||
public String realname_operation = "NONE";
|
||||
public boolean realperson_required = false;
|
||||
public boolean safe_mobile_required = false;
|
||||
}
|
||||
|
||||
public static class VerifyAccountData {
|
||||
public String uid;
|
||||
public String name = "";
|
||||
public String email = "";
|
||||
public String mobile = "";
|
||||
public String is_email_verify = "0";
|
||||
public String realname = "";
|
||||
public String identity_card = "";
|
||||
public String token;
|
||||
public String safe_mobile = "";
|
||||
public String facebook_name = "";
|
||||
public String twitter_name = "";
|
||||
public String game_center_name = "";
|
||||
public String google_name = "";
|
||||
public String apple_name = "";
|
||||
public String sony_name = "";
|
||||
public String tap_name = "";
|
||||
public String country = "US";
|
||||
public String reactivate_ticket = "";
|
||||
public String area_code = "**";
|
||||
public String device_grant_ticket = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package emu.grasscutter.server.http.objects;
|
||||
|
||||
public class LoginTokenRequestJson {
|
||||
public String uid;
|
||||
public String token;
|
||||
public String uid;
|
||||
public String token;
|
||||
}
|
||||
|
||||
@@ -6,21 +6,13 @@ import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.Handler;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
|
||||
public class WebStaticVersionResponse implements Handler {
|
||||
|
||||
@Override
|
||||
public void handle(Context ctx) throws IOException {
|
||||
String requestFor = ctx.path().substring(ctx.path().lastIndexOf("-") + 1);
|
||||
|
||||
getPageResources("/webstatic/" + requestFor, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
private static void getPageResources(String path, Context ctx) {
|
||||
try (InputStream filestream = FileUtils.readResourceAsStream(path)) {
|
||||
ContentType fromExtension = ContentType.getContentTypeByExtension(path.substring(path.lastIndexOf(".") + 1));
|
||||
@@ -33,4 +25,11 @@ public class WebStaticVersionResponse implements Handler {
|
||||
ctx.status(404);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Context ctx) throws IOException {
|
||||
String requestFor = ctx.path().substring(ctx.path().lastIndexOf("-") + 1);
|
||||
|
||||
getPageResources("/webstatic/" + requestFor, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user