Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
ziqian zhang
Grasscutter
Commits
3adf0d44
Commit
3adf0d44
authored
May 13, 2022
by
KingRainbow44
Browse files
Refactor dispatch (now called HTTP) server (pt. 2)
parent
840f4706
Changes
25
Show whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/Grasscutter.java
View file @
3adf0d44
...
@@ -11,9 +11,7 @@ import emu.grasscutter.plugin.api.ServerHook;
...
@@ -11,9 +11,7 @@ import emu.grasscutter.plugin.api.ServerHook;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.server.http.HttpServer
;
import
emu.grasscutter.server.http.HttpServer
;
import
emu.grasscutter.server.http.dispatch.DispatchHandler
;
import
emu.grasscutter.server.http.dispatch.DispatchHandler
;
import
emu.grasscutter.server.http.handlers.AnnouncementsHandler
;
import
emu.grasscutter.server.http.handlers.*
;
import
emu.grasscutter.server.http.handlers.GenericHandler
;
import
emu.grasscutter.server.http.handlers.LogHandler
;
import
emu.grasscutter.server.http.dispatch.RegionHandler
;
import
emu.grasscutter.server.http.dispatch.RegionHandler
;
import
emu.grasscutter.utils.ConfigContainer
;
import
emu.grasscutter.utils.ConfigContainer
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
...
@@ -33,7 +31,6 @@ import ch.qos.logback.classic.Logger;
...
@@ -33,7 +31,6 @@ import ch.qos.logback.classic.Logger;
import
emu.grasscutter.data.ResourceLoader
;
import
emu.grasscutter.data.ResourceLoader
;
import
emu.grasscutter.database.DatabaseManager
;
import
emu.grasscutter.database.DatabaseManager
;
import
emu.grasscutter.utils.Language
;
import
emu.grasscutter.utils.Language
;
import
emu.grasscutter.server.dispatch.DispatchServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.tools.Tools
;
import
emu.grasscutter.tools.Tools
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Crypto
;
...
@@ -54,7 +51,6 @@ public final class Grasscutter {
...
@@ -54,7 +51,6 @@ public final class Grasscutter {
private
static
int
day
;
// Current day of week.
private
static
int
day
;
// Current day of week.
private
static
DispatchServer
dispatchServer
;
private
static
HttpServer
httpServer
;
private
static
HttpServer
httpServer
;
private
static
GameServer
gameServer
;
private
static
GameServer
gameServer
;
private
static
PluginManager
pluginManager
;
private
static
PluginManager
pluginManager
;
...
@@ -113,11 +109,10 @@ public final class Grasscutter {
...
@@ -113,11 +109,10 @@ public final class Grasscutter {
authenticationSystem
=
new
DefaultAuthentication
();
authenticationSystem
=
new
DefaultAuthentication
();
// Create server instances.
// Create server instances.
dispatchServer
=
new
DispatchServer
();
httpServer
=
new
HttpServer
();
httpServer
=
new
HttpServer
();
gameServer
=
new
GameServer
();
gameServer
=
new
GameServer
();
// Create a server hook instance with both servers.
// Create a server hook instance with both servers.
new
ServerHook
(
gameServer
,
dispatch
Server
);
new
ServerHook
(
gameServer
,
http
Server
);
// Create plugin manager instance.
// Create plugin manager instance.
pluginManager
=
new
PluginManager
();
pluginManager
=
new
PluginManager
();
...
@@ -129,14 +124,15 @@ public final class Grasscutter {
...
@@ -129,14 +124,15 @@ public final class Grasscutter {
httpServer
.
addRouter
(
GenericHandler
.
class
);
httpServer
.
addRouter
(
GenericHandler
.
class
);
httpServer
.
addRouter
(
AnnouncementsHandler
.
class
);
httpServer
.
addRouter
(
AnnouncementsHandler
.
class
);
httpServer
.
addRouter
(
DispatchHandler
.
class
);
httpServer
.
addRouter
(
DispatchHandler
.
class
);
httpServer
.
addRouter
(
LegacyAuthHandler
.
class
);
httpServer
.
addRouter
(
GachaHandler
.
class
);
// Start servers.
// Start servers.
var
runMode
=
SERVER
.
runMode
;
var
runMode
=
SERVER
.
runMode
;
if
(
runMode
==
ServerRunMode
.
HYBRID
)
{
if
(
runMode
==
ServerRunMode
.
HYBRID
)
{
dispatch
Server
.
start
();
http
Server
.
start
();
gameServer
.
start
();
gameServer
.
start
();
}
else
if
(
runMode
==
ServerRunMode
.
DISPATCH_ONLY
)
{
}
else
if
(
runMode
==
ServerRunMode
.
DISPATCH_ONLY
)
{
dispatchServer
.
start
();
httpServer
.
start
();
httpServer
.
start
();
}
else
if
(
runMode
==
ServerRunMode
.
GAME_ONLY
)
{
}
else
if
(
runMode
==
ServerRunMode
.
GAME_ONLY
)
{
gameServer
.
start
();
gameServer
.
start
();
...
@@ -258,8 +254,8 @@ public final class Grasscutter {
...
@@ -258,8 +254,8 @@ public final class Grasscutter {
return
gson
;
return
gson
;
}
}
public
static
Dispatch
Server
get
Dispatch
Server
()
{
public
static
Http
Server
get
Http
Server
()
{
return
dispatch
Server
;
return
http
Server
;
}
}
public
static
GameServer
getGameServer
()
{
public
static
GameServer
getGameServer
()
{
...
...
src/main/java/emu/grasscutter/command/commands/ReloadCommand.java
View file @
3adf0d44
...
@@ -21,7 +21,7 @@ public final class ReloadCommand implements CommandHandler {
...
@@ -21,7 +21,7 @@ public final class ReloadCommand implements CommandHandler {
Grasscutter
.
getGameServer
().
getGachaManager
().
load
();
Grasscutter
.
getGameServer
().
getGachaManager
().
load
();
Grasscutter
.
getGameServer
().
getDropManager
().
load
();
Grasscutter
.
getGameServer
().
getDropManager
().
load
();
Grasscutter
.
getGameServer
().
getShopManager
().
load
();
Grasscutter
.
getGameServer
().
getShopManager
().
load
();
Grasscutter
.
get
Dispatch
Server
().
loadQueries
();
//
Grasscutter.get
Http
Server().loadQueries();
// Is this practical?
CommandHandler
.
sendMessage
(
sender
,
translate
(
sender
,
"commands.reload.reload_done"
));
CommandHandler
.
sendMessage
(
sender
,
translate
(
sender
,
"commands.reload.reload_done"
));
}
}
...
...
src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
View file @
3adf0d44
...
@@ -98,9 +98,9 @@ public class GachaBanner {
...
@@ -98,9 +98,9 @@ public class GachaBanner {
}
}
public
GachaInfo
toProto
(
String
sessionKey
)
{
public
GachaInfo
toProto
(
String
sessionKey
)
{
String
record
=
"http"
+
(
DISPATCH_INFO
.
encryption
.
useInRouting
?
"s"
:
""
)
+
"://"
String
record
=
"http"
+
(
HTTP_ENCRYPTION
.
useInRouting
?
"s"
:
""
)
+
"://"
+
lr
(
DISPATCH
_INFO
.
accessAddress
,
DISPATCH
_INFO
.
bindAddress
)
+
":"
+
lr
(
HTTP
_INFO
.
accessAddress
,
HTTP
_INFO
.
bindAddress
)
+
":"
+
lr
(
DISPATCH
_INFO
.
accessPort
,
DISPATCH
_INFO
.
bindPort
)
+
lr
(
HTTP
_INFO
.
accessPort
,
HTTP
_INFO
.
bindPort
)
+
"/gacha?s="
+
sessionKey
+
"&gachaType="
+
gachaType
;
+
"/gacha?s="
+
sessionKey
+
"&gachaType="
+
gachaType
;
// Grasscutter.getLogger().info("record = " + record);
// Grasscutter.getLogger().info("record = " + record);
GachaInfo
.
Builder
info
=
GachaInfo
.
newBuilder
()
GachaInfo
.
Builder
info
=
GachaInfo
.
newBuilder
()
...
...
src/main/java/emu/grasscutter/plugin/api/ServerHook.java
View file @
3adf0d44
package
emu.grasscutter.plugin.api
;
package
emu.grasscutter.plugin.api
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.auth.AuthenticationSystem
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.server.dispatch.DispatchServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.http.HttpServer
;
import
emu.grasscutter.server.http.Router
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.List
;
...
@@ -15,7 +18,7 @@ import java.util.List;
...
@@ -15,7 +18,7 @@ import java.util.List;
public
final
class
ServerHook
{
public
final
class
ServerHook
{
private
static
ServerHook
instance
;
private
static
ServerHook
instance
;
private
final
GameServer
gameServer
;
private
final
GameServer
gameServer
;
private
final
DispatchServer
dispatch
Server
;
private
final
HttpServer
http
Server
;
/**
/**
* Gets the server hook instance.
* Gets the server hook instance.
...
@@ -28,11 +31,11 @@ public final class ServerHook {
...
@@ -28,11 +31,11 @@ public final class ServerHook {
/**
/**
* Hooks into a server.
* Hooks into a server.
* @param gameServer The game server to hook into.
* @param gameServer The game server to hook into.
* @param
dispatch
Server The
dispatch
server to hook into.
* @param
http
Server The
HTTP
server to hook into.
*/
*/
public
ServerHook
(
GameServer
gameServer
,
DispatchServer
dispatch
Server
)
{
public
ServerHook
(
GameServer
gameServer
,
HttpServer
http
Server
)
{
this
.
gameServer
=
gameServer
;
this
.
gameServer
=
gameServer
;
this
.
dispatch
Server
=
dispatch
Server
;
this
.
http
Server
=
http
Server
;
instance
=
this
;
instance
=
this
;
}
}
...
@@ -45,10 +48,10 @@ public final class ServerHook {
...
@@ -45,10 +48,10 @@ public final class ServerHook {
}
}
/**
/**
* @return The
dispatch
server.
* @return The
HTTP
server.
*/
*/
public
Dispatch
Server
get
Dispatch
Server
()
{
public
Http
Server
get
Http
Server
()
{
return
this
.
dispatch
Server
;
return
this
.
http
Server
;
}
}
/**
/**
...
@@ -70,4 +73,28 @@ public final class ServerHook {
...
@@ -70,4 +73,28 @@ public final class ServerHook {
Command
commandData
=
clazz
.
getAnnotation
(
Command
.
class
);
Command
commandData
=
clazz
.
getAnnotation
(
Command
.
class
);
this
.
gameServer
.
getCommandMap
().
registerCommand
(
commandData
.
label
(),
handler
);
this
.
gameServer
.
getCommandMap
().
registerCommand
(
commandData
.
label
(),
handler
);
}
}
/**
* Adds a router using an instance of a class.
* @param router A router instance.
*/
public
void
addRouter
(
Router
router
)
{
this
.
addRouter
(
router
.
getClass
());
}
/**
* Adds a router using a class.
* @param router The class of the router.
*/
public
void
addRouter
(
Class
<?
extends
Router
>
router
)
{
this
.
httpServer
.
addRouter
(
router
);
}
/**
* Sets the server's authentication system.
* @param authSystem An instance of the authentication system.
*/
public
void
setAuthSystem
(
AuthenticationSystem
authSystem
)
{
Grasscutter
.
setAuthenticationSystem
(
authSystem
);
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/scripts/serializer/LuaSerializer.java
View file @
3adf0d44
...
@@ -70,15 +70,13 @@ public class LuaSerializer implements Serializer {
...
@@ -70,15 +70,13 @@ public class LuaSerializer implements Serializer {
}
}
try
{
try
{
//noinspection ConfusingArgumentToVarargsMethod
object
=
type
.
getDeclaredConstructor
().
newInstance
(
null
);
object
=
type
.
getDeclaredConstructor
().
newInstance
(
null
);
LuaValue
[]
keys
=
table
.
keys
();
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
for
(
LuaValue
k
:
keys
)
{
try
{
try
{
Field
field
=
object
.
getClass
().
getDeclaredField
(
k
.
checkjstring
());
Field
field
=
object
.
getClass
().
getDeclaredField
(
k
.
checkjstring
());
if
(
field
==
null
)
{
continue
;
}
field
.
setAccessible
(
true
);
field
.
setAccessible
(
true
);
LuaValue
keyValue
=
table
.
get
(
k
);
LuaValue
keyValue
=
table
.
get
(
k
);
...
...
src/main/java/emu/grasscutter/server/dispatch/AnnouncementHandler.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch
;
import
emu.grasscutter.Grasscutter
;
import
express.http.HttpContextHandler
;
import
express.http.Request
;
import
express.http.Response
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.util.Objects
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
final
class
AnnouncementHandler
implements
HttpContextHandler
{
@Override
public
void
handle
(
Request
request
,
Response
response
)
throws
IOException
{
//event
if
(
Objects
.
equals
(
request
.
baseUrl
(),
"/common/hk4e_global/announcement/api/getAnnContent"
))
{
response
.
send
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":"
+
readToString
(
new
File
(
DATA
(
"GameAnnouncement.json"
)))
+
"}"
);
}
else
if
(
Objects
.
equals
(
request
.
baseUrl
(),
"/common/hk4e_global/announcement/api/getAnnList"
))
{
String
data
=
readToString
(
new
File
(
DATA
(
"GameAnnouncementList.json"
))).
replace
(
"System.currentTimeMillis()"
,
String
.
valueOf
(
System
.
currentTimeMillis
()));
response
.
send
(
"{\"retcode\":0,\"message\":\"OK\",\"data\": "
+
data
+
"}"
);
}
}
@SuppressWarnings
(
"ResultOfMethodCallIgnored"
)
private
static
String
readToString
(
File
file
)
{
long
length
=
file
.
length
();
byte
[]
content
=
new
byte
[(
int
)
length
];
try
{
FileInputStream
in
=
new
FileInputStream
(
file
);
in
.
read
(
content
);
in
.
close
();
}
catch
(
IOException
ignored
)
{
Grasscutter
.
getLogger
().
warn
(
"File not found: "
+
file
.
getAbsolutePath
());
}
return
new
String
(
content
);
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/dispatch/ClientLogHandler.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch
;
import
express.http.HttpContextHandler
;
import
express.http.Request
;
import
express.http.Response
;
import
java.io.IOException
;
/**
* Used for processing crash dumps and logs generated by the game.
* Logs are in JSON, and are sent to the server for logging.
*/
public
final
class
ClientLogHandler
implements
HttpContextHandler
{
@Override
public
void
handle
(
Request
request
,
Response
response
)
throws
IOException
{
// TODO: Figure out how to dump request body and log to file.
response
.
send
(
"{\"code\":0}"
);
}
}
src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
com.google.protobuf.ByteString
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter.ServerDebugMode
;
import
emu.grasscutter.Grasscutter.ServerRunMode
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp
;
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.dispatch.authentication.AuthenticationHandler
;
import
emu.grasscutter.server.dispatch.authentication.DefaultAuthenticationHandler
;
import
emu.grasscutter.server.dispatch.http.GachaRecordHandler
;
import
emu.grasscutter.server.dispatch.json.*
;
import
emu.grasscutter.server.dispatch.json.ComboTokenReqJson.LoginTokenData
;
import
emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent
;
import
emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent
;
import
emu.grasscutter.tools.Tools
;
import
emu.grasscutter.utils.FileUtils
;
import
emu.grasscutter.utils.Utils
;
import
express.Express
;
import
io.javalin.http.staticfiles.Location
;
import
org.eclipse.jetty.server.Connector
;
import
org.eclipse.jetty.server.Server
;
import
org.eclipse.jetty.server.ServerConnector
;
import
org.eclipse.jetty.util.ssl.SslContextFactory
;
import
java.io.*
;
import
java.net.URLDecoder
;
import
java.nio.charset.StandardCharsets
;
import
java.util.*
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
final
class
DispatchServer
{
public
static
String
query_region_list
=
""
;
public
static
String
query_cur_region
=
""
;
private
final
Gson
gson
;
private
final
String
defaultServerName
=
"os_usa"
;
public
String
regionListBase64
;
public
Map
<
String
,
RegionData
>
regions
;
private
AuthenticationHandler
authHandler
;
private
Express
httpServer
;
public
DispatchServer
()
{
this
.
regions
=
new
HashMap
<>();
this
.
gson
=
new
GsonBuilder
().
create
();
this
.
loadQueries
();
this
.
initRegion
();
}
public
Express
getServer
()
{
return
httpServer
;
}
public
void
setHttpServer
(
Express
httpServer
)
{
this
.
httpServer
.
stop
();
this
.
httpServer
=
httpServer
;
this
.
httpServer
.
listen
(
DISPATCH_INFO
.
bindPort
);
}
public
Gson
getGsonFactory
()
{
return
gson
;
}
public
QueryCurrRegionHttpRsp
getCurrRegion
()
{
// Needs to be fixed by having the game servers connect to the dispatch server.
if
(
SERVER
.
runMode
==
ServerRunMode
.
HYBRID
)
{
return
regions
.
get
(
defaultServerName
).
parsedRegionQuery
;
}
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] Unsupported run mode for getCurrRegion()"
);
return
null
;
}
public
void
loadQueries
()
{
File
file
;
file
=
new
File
(
DATA
(
"query_region_list.txt"
));
if
(
file
.
exists
())
{
query_region_list
=
new
String
(
FileUtils
.
read
(
file
));
}
else
{
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] query_region_list not found! Using default region list."
);
}
file
=
new
File
(
DATA
(
"query_cur_region.txt"
));
if
(
file
.
exists
())
{
query_cur_region
=
new
String
(
FileUtils
.
read
(
file
));
}
else
{
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] query_cur_region not found! Using default current region."
);
}
}
private
void
initRegion
()
{
try
{
byte
[]
decoded
=
Base64
.
getDecoder
().
decode
(
query_region_list
);
QueryRegionListHttpRsp
rl
=
QueryRegionListHttpRsp
.
parseFrom
(
decoded
);
byte
[]
decoded2
=
Base64
.
getDecoder
().
decode
(
query_cur_region
);
QueryCurrRegionHttpRsp
regionQuery
=
QueryCurrRegionHttpRsp
.
parseFrom
(
decoded2
);
List
<
RegionSimpleInfo
>
servers
=
new
ArrayList
<>();
List
<
String
>
usedNames
=
new
ArrayList
<>();
// List to check for potential naming conflicts.
if
(
SERVER
.
runMode
==
ServerRunMode
.
HYBRID
)
{
// Automatically add the game server if in hybrid mode.
RegionSimpleInfo
server
=
RegionSimpleInfo
.
newBuilder
()
.
setName
(
"os_usa"
)
.
setTitle
(
DISPATCH_INFO
.
defaultName
)
.
setType
(
"DEV_PUBLIC"
)
.
setDispatchUrl
(
"http"
+
(
HTTP_ENCRYPTION
.
useInRouting
?
"s"
:
""
)
+
"://"
+
lr
(
DISPATCH_INFO
.
accessAddress
,
DISPATCH_INFO
.
bindAddress
)
+
":"
+
lr
(
DISPATCH_INFO
.
accessPort
,
DISPATCH_INFO
.
bindPort
)
+
"/query_cur_region/"
+
defaultServerName
)
.
build
();
usedNames
.
add
(
defaultServerName
);
servers
.
add
(
server
);
RegionInfo
serverRegion
=
regionQuery
.
getRegionInfo
().
toBuilder
()
.
setGateserverIp
(
lr
(
GAME_INFO
.
accessAddress
,
GAME_INFO
.
bindAddress
))
.
setGateserverPort
(
lr
(
GAME_INFO
.
accessPort
,
GAME_INFO
.
bindPort
))
.
setSecretKey
(
ByteString
.
copyFrom
(
FileUtils
.
read
(
KEYS_FOLDER
+
"/dispatchSeed.bin"
)))
.
build
();
QueryCurrRegionHttpRsp
parsedRegionQuery
=
regionQuery
.
toBuilder
().
setRegionInfo
(
serverRegion
).
build
();
regions
.
put
(
defaultServerName
,
new
RegionData
(
parsedRegionQuery
,
Base64
.
getEncoder
().
encodeToString
(
parsedRegionQuery
.
toByteString
().
toByteArray
())));
}
else
if
(
DISPATCH_INFO
.
regions
.
length
==
0
)
{
Grasscutter
.
getLogger
().
error
(
"[Dispatch] There are no game servers available. Exiting due to unplayable state."
);
System
.
exit
(
1
);
}
for
(
var
regionInfo
:
DISPATCH_INFO
.
regions
)
{
if
(
usedNames
.
contains
(
regionInfo
.
Name
))
{
Grasscutter
.
getLogger
().
error
(
"Region name already in use."
);
continue
;
}
RegionSimpleInfo
server
=
RegionSimpleInfo
.
newBuilder
()
.
setName
(
regionInfo
.
Name
)
.
setTitle
(
regionInfo
.
Title
)
.
setType
(
"DEV_PUBLIC"
)
.
setDispatchUrl
(
"http"
+
(
HTTP_ENCRYPTION
.
useInRouting
?
"s"
:
""
)
+
"://"
+
lr
(
DISPATCH_INFO
.
accessAddress
,
DISPATCH_INFO
.
bindAddress
)
+
":"
+
lr
(
DISPATCH_INFO
.
accessPort
,
DISPATCH_INFO
.
bindPort
)
+
"/query_cur_region/"
+
regionInfo
.
Name
)
.
build
();
usedNames
.
add
(
regionInfo
.
Name
);
servers
.
add
(
server
);
RegionInfo
serverRegion
=
regionQuery
.
getRegionInfo
().
toBuilder
()
.
setGateserverIp
(
regionInfo
.
Ip
)
.
setGateserverPort
(
regionInfo
.
Port
)
.
setSecretKey
(
ByteString
.
copyFrom
(
FileUtils
.
read
(
KEYS_FOLDER
+
"/dispatchSeed.bin"
)))
.
build
();
QueryCurrRegionHttpRsp
parsedRegionQuery
=
regionQuery
.
toBuilder
().
setRegionInfo
(
serverRegion
).
build
();
regions
.
put
(
regionInfo
.
Name
,
new
RegionData
(
parsedRegionQuery
,
Base64
.
getEncoder
().
encodeToString
(
parsedRegionQuery
.
toByteString
().
toByteArray
())));
}
QueryRegionListHttpRsp
regionList
=
QueryRegionListHttpRsp
.
newBuilder
()
.
addAllRegionList
(
servers
)
.
setClientSecretKey
(
rl
.
getClientSecretKey
())
.
setClientCustomConfigEncrypted
(
rl
.
getClientCustomConfigEncrypted
())
.
setEnableLoginPc
(
true
)
.
build
();
this
.
regionListBase64
=
Base64
.
getEncoder
().
encodeToString
(
regionList
.
toByteString
().
toByteArray
());
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"[Dispatch] Error while initializing region info!"
,
exception
);
}
}
public
void
start
()
throws
Exception
{
httpServer
=
new
Express
(
config
->
{
config
.
server
(()
->
{
Server
server
=
new
Server
();
ServerConnector
serverConnector
;
if
(
HTTP_ENCRYPTION
.
useEncryption
)
{
SslContextFactory
.
Server
sslContextFactory
=
new
SslContextFactory
.
Server
();
File
keystoreFile
=
new
File
(
HTTP_ENCRYPTION
.
keystore
);
if
(
keystoreFile
.
exists
())
{
try
{
sslContextFactory
.
setKeyStorePath
(
keystoreFile
.
getPath
());
sslContextFactory
.
setKeyStorePassword
(
HTTP_ENCRYPTION
.
keystorePassword
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
Grasscutter
.
getLogger
().
warn
(
translate
(
"messages.dispatch.keystore.password_error"
));
try
{
sslContextFactory
.
setKeyStorePath
(
keystoreFile
.
getPath
());
sslContextFactory
.
setKeyStorePassword
(
"123456"
);
Grasscutter
.
getLogger
().
warn
(
translate
(
"messages.dispatch.keystore.default_password"
));
}
catch
(
Exception
e2
)
{
Grasscutter
.
getLogger
().
warn
(
translate
(
"messages.dispatch.keystore.general_error"
));
e2
.
printStackTrace
();
}
}
serverConnector
=
new
ServerConnector
(
server
,
sslContextFactory
);
}
else
{
Grasscutter
.
getLogger
().
warn
(
translate
(
"messages.dispatch.keystore.no_keystore_error"
));
HTTP_ENCRYPTION
.
useEncryption
=
false
;
serverConnector
=
new
ServerConnector
(
server
);
}
}
else
{
serverConnector
=
new
ServerConnector
(
server
);
}
serverConnector
.
setPort
(
DISPATCH_INFO
.
bindPort
);
server
.
setConnectors
(
new
Connector
[]{
serverConnector
});
return
server
;
});
config
.
enforceSsl
=
HTTP_ENCRYPTION
.
useEncryption
;
if
(
SERVER
.
debugLevel
==
ServerDebugMode
.
ALL
)
{
config
.
enableDevLogging
();
}
if
(
HTTP_POLICIES
.
cors
.
enabled
)
{
var
corsPolicy
=
HTTP_POLICIES
.
cors
;
if
(
corsPolicy
.
allowedOrigins
.
length
>
0
)
config
.
enableCorsForOrigin
(
corsPolicy
.
allowedOrigins
);
else
config
.
enableCorsForAllOrigins
();
}
});
httpServer
.
get
(
"/"
,
(
req
,
res
)
->
res
.
send
(
"<!doctype html><html><head><meta charset=\"utf8\"></head><body>"
+
translate
(
"messages.status.welcome"
)
+
"</body></html>"
));
httpServer
.
raw
().
error
(
404
,
ctx
->
{
if
(
SERVER
.
debugLevel
==
ServerDebugMode
.
MISSING
)
{
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.unhandled_request_error"
,
ctx
.
method
(),
ctx
.
url
()));
}
ctx
.
contentType
(
"text/html"
);
ctx
.
result
(
"<!doctype html><html><head><meta charset=\"utf8\"></head><body><img src=\"https://http.cat/404\" /></body></html>"
);
// I'm like 70% sure this won't break anything.
});
// Authentication Handler
// These routes are so that authentication routes are always the same no matter what auth system is used.
httpServer
.
get
(
"/authentication/type"
,
(
req
,
res
)
->
{
res
.
send
(
this
.
getAuthHandler
().
getClass
().
getName
());
});
httpServer
.
post
(
"/authentication/login"
,
(
req
,
res
)
->
this
.
getAuthHandler
().
handleLogin
(
req
,
res
));
httpServer
.
post
(
"/authentication/register"
,
(
req
,
res
)
->
this
.
getAuthHandler
().
handleRegister
(
req
,
res
));
httpServer
.
post
(
"/authentication/change_password"
,
(
req
,
res
)
->
this
.
getAuthHandler
().
handleChangePassword
(
req
,
res
));
// Server Status
httpServer
.
get
(
"/status/server"
,
(
req
,
res
)
->
{
int
playerCount
=
Grasscutter
.
getGameServer
().
getPlayers
().
size
();
String
version
=
GameConstants
.
VERSION
;
res
.
send
(
"{\"retcode\":0,\"status\":{\"playerCount\":"
+
playerCount
+
",\"version\":\""
+
version
+
"\"}}"
);
});
// Dispatch
httpServer
.
get
(
"/query_region_list"
,
(
req
,
res
)
->
{
// Log
Grasscutter
.
getLogger
().
info
(
String
.
format
(
"[Dispatch] Client %s request: query_region_list"
,
req
.
ip
()));
// Invoke event.
QueryAllRegionsEvent
event
=
new
QueryAllRegionsEvent
(
regionListBase64
);
event
.
call
();
// Respond with event result.
res
.
send
(
event
.
getRegionList
());
});
// /server/:id -> 2.6.5x
httpServer
.
get
(
"/query_cur_region/:id"
,
(
req
,
res
)
->
{
String
regionName
=
req
.
params
(
"id"
);
// Log
Grasscutter
.
getLogger
().
info
(
String
.
format
(
"Client %s request: query_cur_region/%s"
,
req
.
ip
(),
regionName
));
// Create a response form the request query parameters
String
response
=
"CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
;
if
(
req
.
query
().
values
().
size
()
>
0
)
{
response
=
regions
.
get
(
regionName
).
Base64
;
}
// Invoke event.
QueryCurrentRegionEvent
event
=
new
QueryCurrentRegionEvent
(
response
);
event
.
call
();
// Respond with event result.
res
.
send
(
event
.
getRegionInfo
());
});
// Login
httpServer
.
post
(
"/hk4e_global/mdk/shield/api/login"
,
(
req
,
res
)
->
{
// Get post data
LoginAccountRequestJson
requestData
=
null
;
try
{
String
body
=
req
.
ctx
().
body
();
requestData
=
getGsonFactory
().
fromJson
(
body
,
LoginAccountRequestJson
.
class
);
}
catch
(
Exception
ignored
)
{
}
// Create response json
if
(
requestData
==
null
)
{
return
;
}
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.login_attempt"
,
req
.
ip
()));
res
.
send
(
this
.
getAuthHandler
().
handleGameLogin
(
req
,
requestData
));
});
// Login via token
httpServer
.
post
(
"/hk4e_global/mdk/shield/api/verify"
,
(
req
,
res
)
->
{
// Get post data
LoginTokenRequestJson
requestData
=
null
;
try
{
String
body
=
req
.
ctx
().
body
();
requestData
=
getGsonFactory
().
fromJson
(
body
,
LoginTokenRequestJson
.
class
);
}
catch
(
Exception
ignored
)
{
}
// Create response json
if
(
requestData
==
null
)
{
return
;
}
LoginResultJson
responseData
=
new
LoginResultJson
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.login_token_attempt"
,
req
.
ip
()));
// Login
Account
account
=
DatabaseHelper
.
getAccountById
(
requestData
.
uid
);
// Test
if
(
account
==
null
||
!
account
.
getSessionKey
().
equals
(
requestData
.
token
))
{
responseData
.
retcode
=
-
111
;
responseData
.
message
=
translate
(
"messages.dispatch.account.account_cache_error"
);
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.login_token_error"
,
req
.
ip
()));
}
else
{
responseData
.
message
=
"OK"
;
responseData
.
data
.
account
.
uid
=
requestData
.
uid
;
responseData
.
data
.
account
.
token
=
requestData
.
token
;
responseData
.
data
.
account
.
email
=
account
.
getEmail
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.login_token_success"
,
req
.
ip
(),
requestData
.
uid
));
}
res
.
send
(
responseData
);
});
// Exchange for combo token
httpServer
.
post
(
"/hk4e_global/combo/granter/login/v2/login"
,
(
req
,
res
)
->
{
// Get post data
ComboTokenReqJson
requestData
=
null
;
try
{
String
body
=
req
.
ctx
().
body
();
requestData
=
getGsonFactory
().
fromJson
(
body
,
ComboTokenReqJson
.
class
);
}
catch
(
Exception
ignored
)
{
}
// Create response json
if
(
requestData
==
null
||
requestData
.
data
==
null
)
{
return
;
}
LoginTokenData
loginData
=
getGsonFactory
().
fromJson
(
requestData
.
data
,
LoginTokenData
.
class
);
// Get login
// data
ComboTokenResJson
responseData
=
new
ComboTokenResJson
();
// Login
Account
account
=
DatabaseHelper
.
getAccountById
(
loginData
.
uid
);
// Test
if
(
account
==
null
||
!
account
.
getSessionKey
().
equals
(
loginData
.
token
))
{
responseData
.
retcode
=
-
201
;
responseData
.
message
=
translate
(
"messages.dispatch.account.session_key_error"
);
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.combo_token_error"
,
req
.
ip
()));
}
else
{
responseData
.
message
=
"OK"
;
responseData
.
data
.
open_id
=
loginData
.
uid
;
responseData
.
data
.
combo_id
=
"157795300"
;
responseData
.
data
.
combo_token
=
account
.
generateLoginToken
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.combo_token_success"
,
req
.
ip
()));
}
res
.
send
(
responseData
);
});
// TODO: There are some missing route request types here (You can tell if they are missing if they are .all and not anything else)
// When http requests for theses routes are found please remove it from the list in DispatchHttpJsonHandler and update the route request types here
// Agreement and Protocol
// hk4e-sdk-os.hoyoverse.com
httpServer
.
get
(
"/hk4e_global/mdk/agreement/api/getAgreementInfos"
,
new
DispatchHttpJsonHandler
(
"{\"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
httpServer
.
all
(
"/hk4e_global/combo/granter/api/compareProtocolVersion"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"modified\":true,\"protocol\":{\"id\":0,\"app_id\":4,\"language\":\"en\",\"user_proto\":\"\",\"priv_proto\":\"\",\"major\":7,\"minimum\":0,\"create_time\":\"0\",\"teenager_proto\":\"\",\"third_proto\":\"\"}}}"
));
// Game data
// hk4e-api-os.hoyoverse.com
httpServer
.
all
(
"/common/hk4e_global/announcement/api/getAlertPic"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"total\":0,\"list\":[]}}"
));
// hk4e-api-os.hoyoverse.com
httpServer
.
all
(
"/common/hk4e_global/announcement/api/getAlertAnn"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"alert\":false,\"alert_id\":0,\"remind\":true}}"
));
// hk4e-api-os.hoyoverse.com
httpServer
.
all
(
"/common/hk4e_global/announcement/api/getAnnList"
,
new
AnnouncementHandler
());
// hk4e-api-os-static.hoyoverse.com
httpServer
.
all
(
"/common/hk4e_global/announcement/api/getAnnContent"
,
new
AnnouncementHandler
());
// hk4e-sdk-os.hoyoverse.com
httpServer
.
all
(
"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}"
));
// Captcha
// api-account-os.hoyoverse.com
httpServer
.
post
(
"/account/risky/api/check"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"none\",\"action\":\"ACTION_NONE\",\"geetest\":null}}"
));
// Config
// sdk-os-static.hoyoverse.com
httpServer
.
get
(
"/combo/box/api/config/sdk/combo"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"vals\":{\"disable_email_bind_skip\":\"false\",\"email_bind_remind_interval\":\"7\",\"email_bind_remind\":\"true\"}}}"
));
// hk4e-sdk-os-static.hoyoverse.com
httpServer
.
get
(
"/hk4e_global/combo/granter/api/getConfig"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"protocol\":true,\"qr_enabled\":false,\"log_level\":\"INFO\",\"announce_url\":\"https://webstatic-sea.hoyoverse.com/hk4e/announcement/index.html?sdk_presentation_style=fullscreen\\u0026sdk_screen_transparent=true\\u0026game_biz=hk4e_global\\u0026auth_appid=announcement\\u0026game=hk4e#/\",\"push_alias_type\":2,\"disable_ysdk_guard\":false,\"enable_announce_pic_popup\":true}}"
));
// hk4e-sdk-os-static.hoyoverse.com
httpServer
.
get
(
"/hk4e_global/mdk/shield/api/loadConfig"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":6,\"game_key\":\"hk4e_global\",\"client\":\"PC\",\"identity\":\"I_IDENTITY\",\"guest\":false,\"ignore_versions\":\"\",\"scene\":\"S_NORMAL\",\"name\":\"原神海外\",\"disable_regist\":false,\"enable_email_captcha\":false,\"thirdparty\":[\"fb\",\"tw\"],\"disable_mmt\":false,\"server_guest\":false,\"thirdparty_ignore\":{\"tw\":\"\",\"fb\":\"\"},\"enable_ps_bind_account\":false,\"thirdparty_login_configs\":{\"tw\":{\"token_type\":\"TK_GAME_TOKEN\",\"game_token_expires_in\":604800},\"fb\":{\"token_type\":\"TK_GAME_TOKEN\",\"game_token_expires_in\":604800}}}}"
));
// Test api?
// abtest-api-data-sg.hoyoverse.com
httpServer
.
post
(
"/data_abtest_api/config/experiment/list"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"success\":true,\"message\":\"\",\"data\":[{\"code\":1000,\"type\":2,\"config_id\":\"14\",\"period_id\":\"6036_99\",\"version\":\"1\",\"configs\":{\"cardType\":\"old\"}}]}"
));
// log-upload-os.mihoyo.com
httpServer
.
all
(
"/log/sdk/upload"
,
new
DispatchHttpJsonHandler
(
"{\"code\":0}"
));
httpServer
.
all
(
"/sdk/upload"
,
new
DispatchHttpJsonHandler
(
"{\"code\":0}"
));
httpServer
.
post
(
"/sdk/dataUpload"
,
new
DispatchHttpJsonHandler
(
"{\"code\":0}"
));
// /perf/config/verify?device_id=xxx&platform=x&name=xxx
httpServer
.
all
(
"/perf/config/verify"
,
new
DispatchHttpJsonHandler
(
"{\"code\":0}"
));
// Logging servers
// overseauspider.yuanshen.com
httpServer
.
all
(
"/log"
,
new
ClientLogHandler
());
// log-upload-os.mihoyo.com
httpServer
.
all
(
"/crash/dataUpload"
,
new
ClientLogHandler
());
// webstatic-sea.hoyoverse.com
httpServer
.
get
(
"/admin/mi18n/plat_oversea/m202003048/m202003048-version.json"
,
new
DispatchHttpJsonHandler
(
"{\"version\":51}"
));
// gacha record.
String
gachaMappingsPath
=
Utils
.
toFilePath
(
DATA
(
"/gacha_mappings.js"
));
// TODO: Only serve the html page and have a subsequent request to fetch the gacha data.
httpServer
.
get
(
"/gacha"
,
new
GachaRecordHandler
());
if
(!(
new
File
(
gachaMappingsPath
).
exists
()))
{
Tools
.
createGachaMapping
(
gachaMappingsPath
);
}
httpServer
.
raw
().
config
.
addSinglePageRoot
(
"/gacha/mappings"
,
gachaMappingsPath
,
Location
.
EXTERNAL
);
// static file support for plugins
httpServer
.
raw
().
config
.
precompressStaticFiles
=
false
;
// If this isn't set to false, files such as images may appear corrupted when serving static files
httpServer
.
listen
(
DISPATCH_INFO
.
bindPort
);
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.port_bind"
,
Integer
.
toString
(
httpServer
.
raw
().
port
())));
}
private
Map
<
String
,
String
>
parseQueryString
(
String
qs
)
{
Map
<
String
,
String
>
result
=
new
HashMap
<>();
if
(
qs
==
null
)
{
return
result
;
}
int
last
=
0
,
next
,
l
=
qs
.
length
();
while
(
last
<
l
)
{
next
=
qs
.
indexOf
(
'&'
,
last
);
if
(
next
==
-
1
)
{
next
=
l
;
}
if
(
next
>
last
)
{
int
eqPos
=
qs
.
indexOf
(
'='
,
last
);
if
(
eqPos
<
0
||
eqPos
>
next
)
{
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
next
),
StandardCharsets
.
UTF_8
),
""
);
}
else
{
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
eqPos
),
StandardCharsets
.
UTF_8
),
URLDecoder
.
decode
(
qs
.
substring
(
eqPos
+
1
,
next
),
StandardCharsets
.
UTF_8
));
}
}
last
=
next
+
1
;
}
return
result
;
}
public
AuthenticationHandler
getAuthHandler
()
{
if
(
authHandler
==
null
)
{
return
new
DefaultAuthenticationHandler
();
}
return
authHandler
;
}
public
boolean
registerAuthHandler
(
AuthenticationHandler
authHandler
)
{
if
(
this
.
authHandler
!=
null
)
{
Grasscutter
.
getLogger
().
error
(
String
.
format
(
"[Dispatch] Unable to register '%s' authentication handler. \n"
+
"The '%s' authentication handler has already been registered"
,
authHandler
.
getClass
().
getName
(),
this
.
authHandler
.
getClass
().
getName
()));
return
false
;
}
this
.
authHandler
=
authHandler
;
return
true
;
}
public
void
resetAuthHandler
()
{
this
.
authHandler
=
null
;
}
public
static
class
RegionData
{
QueryCurrRegionHttpRsp
parsedRegionQuery
;
String
Base64
;
public
RegionData
(
QueryCurrRegionHttpRsp
prq
,
String
b64
)
{
this
.
parsedRegionQuery
=
prq
;
this
.
Base64
=
b64
;
}
public
QueryCurrRegionHttpRsp
getParsedRegionQuery
()
{
return
parsedRegionQuery
;
}
public
String
getBase64
()
{
return
Base64
;
}
}
}
src/main/java/emu/grasscutter/server/dispatch/authentication/AuthenticationHandler.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.authentication
;
import
emu.grasscutter.server.dispatch.json.LoginAccountRequestJson
;
import
emu.grasscutter.server.dispatch.json.LoginResultJson
;
import
express.http.Request
;
import
express.http.Response
;
public
interface
AuthenticationHandler
{
// This is in case plugins also want some sort of authentication
void
handleLogin
(
Request
req
,
Response
res
);
void
handleRegister
(
Request
req
,
Response
res
);
void
handleChangePassword
(
Request
req
,
Response
res
);
LoginResultJson
handleGameLogin
(
Request
req
,
LoginAccountRequestJson
requestData
);
}
src/main/java/emu/grasscutter/server/dispatch/authentication/DefaultAuthenticationHandler.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.authentication
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.server.dispatch.json.LoginAccountRequestJson
;
import
emu.grasscutter.server.dispatch.json.LoginResultJson
;
import
express.http.Request
;
import
express.http.Response
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
class
DefaultAuthenticationHandler
implements
AuthenticationHandler
{
@Override
public
void
handleLogin
(
Request
req
,
Response
res
)
{
res
.
send
(
"Authentication is not available with the default authentication method"
);
}
@Override
public
void
handleRegister
(
Request
req
,
Response
res
)
{
res
.
send
(
"Authentication is not available with the default authentication method"
);
}
@Override
public
void
handleChangePassword
(
Request
req
,
Response
res
)
{
res
.
send
(
"Authentication is not available with the default authentication method"
);
}
@Override
public
LoginResultJson
handleGameLogin
(
Request
req
,
LoginAccountRequestJson
requestData
)
{
LoginResultJson
responseData
=
new
LoginResultJson
();
// Login
Account
account
=
DatabaseHelper
.
getAccountByName
(
requestData
.
account
);
// Check if account exists, else create a new one.
if
(
account
==
null
)
{
// Account doesn't exist, so we can either auto create it if the config value is set.
if
(
ACCOUNT
.
autoCreate
)
{
// This account has been created AUTOMATICALLY. There will be no permissions added.
account
=
DatabaseHelper
.
createAccountWithId
(
requestData
.
account
,
0
);
for
(
String
permission
:
ACCOUNT
.
defaultPermissions
)
{
account
.
addPermission
(
permission
);
}
if
(
account
!=
null
)
{
responseData
.
message
=
"OK"
;
responseData
.
data
.
account
.
uid
=
account
.
getId
();
responseData
.
data
.
account
.
token
=
account
.
generateSessionKey
();
responseData
.
data
.
account
.
email
=
account
.
getEmail
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.account_login_create_success"
,
req
.
ip
(),
responseData
.
data
.
account
.
uid
));
}
else
{
responseData
.
retcode
=
-
201
;
responseData
.
message
=
translate
(
"messages.dispatch.account.username_create_error"
);
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.account_login_create_error"
,
req
.
ip
()));
}
}
else
{
responseData
.
retcode
=
-
201
;
responseData
.
message
=
translate
(
"messages.dispatch.account.username_error"
);
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.account_login_exist_error"
,
req
.
ip
()));
}
}
else
{
// Account was found, log the player in
responseData
.
message
=
"OK"
;
responseData
.
data
.
account
.
uid
=
account
.
getId
();
responseData
.
data
.
account
.
token
=
account
.
generateSessionKey
();
responseData
.
data
.
account
.
email
=
account
.
getEmail
();
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.dispatch.account.login_success"
,
req
.
ip
(),
responseData
.
data
.
account
.
uid
));
}
return
responseData
;
}
}
src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.http
;
import
java.io.File
;
import
java.io.IOException
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.utils.FileUtils
;
import
emu.grasscutter.utils.Utils
;
import
express.http.HttpContextHandler
;
import
express.http.Request
;
import
express.http.Response
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
final
class
GachaRecordHandler
implements
HttpContextHandler
{
String
render_template
;
public
GachaRecordHandler
()
{
File
template
=
new
File
(
Utils
.
toFilePath
(
DATA
(
"/gacha_records.html"
)));
if
(
template
.
exists
())
{
// Load from cache
render_template
=
new
String
(
FileUtils
.
read
(
template
));
}
else
{
render_template
=
"{{REPLACE_RECORD}}"
;
}
}
@Override
public
void
handle
(
Request
req
,
Response
res
)
throws
IOException
{
// Grasscutter.getLogger().info( req.query().toString() );
String
sessionKey
=
req
.
query
(
"s"
);
int
page
=
0
;
int
gachaType
=
0
;
if
(
req
.
query
(
"p"
)
!=
null
)
{
page
=
Integer
.
parseInt
(
req
.
query
(
"p"
));
}
if
(
req
.
query
(
"gachaType"
)
!=
null
)
{
gachaType
=
Integer
.
parseInt
(
req
.
query
(
"gachaType"
));
}
Account
account
=
DatabaseHelper
.
getAccountBySessionKey
(
sessionKey
);
if
(
account
!=
null
)
{
String
records
=
DatabaseHelper
.
getGachaRecords
(
account
.
getPlayerUid
(),
page
,
gachaType
).
toString
();
// Grasscutter.getLogger().info(records);
String
response
=
render_template
.
replace
(
"{{REPLACE_RECORD}}"
,
records
)
.
replace
(
"{{REPLACE_MAXPAGE}}"
,
String
.
valueOf
(
DatabaseHelper
.
getGachaRecordsMaxPage
(
account
.
getPlayerUid
(),
page
,
gachaType
)));
res
.
send
(
response
);
}
else
{
res
.
send
(
"No account found."
);
}
}
}
src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenReqJson.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.json
;
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
;
}
}
src/main/java/emu/grasscutter/server/dispatch/json/ComboTokenResJson.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.json
;
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
;
// ?
}
}
src/main/java/emu/grasscutter/server/dispatch/json/LoginAccountRequestJson.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.json
;
public
class
LoginAccountRequestJson
{
public
String
account
;
public
String
password
;
public
boolean
is_crypto
;
}
src/main/java/emu/grasscutter/server/dispatch/json/LoginResultJson.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.json
;
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
=
""
;
}
}
src/main/java/emu/grasscutter/server/dispatch/json/LoginTokenRequestJson.java
deleted
100644 → 0
View file @
840f4706
package
emu.grasscutter.server.dispatch.json
;
public
class
LoginTokenRequestJson
{
public
String
uid
;
public
String
token
;
}
src/main/java/emu/grasscutter/server/http/HttpServer.java
View file @
3adf0d44
...
@@ -162,11 +162,11 @@ public final class HttpServer {
...
@@ -162,11 +162,11 @@ public final class HttpServer {
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
<meta charset=
\\
"
utf8
\\
">
<meta charset="
utf8
">
</head>
</head>
<body>
<body>
<img src=
\\
"
https:
//http.cat/404
\\
" />
<img src="
https:
//http.cat/404" />
</
body
>
</
body
>
</
html
>
</
html
>
""
"
);
""
"
);
...
...
src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java
View file @
3adf0d44
...
@@ -151,8 +151,10 @@ public final class RegionHandler implements Router {
...
@@ -151,8 +151,10 @@ public final class RegionHandler implements Router {
// Get region data.
// Get region data.
String
regionData
=
"CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
;
String
regionData
=
"CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="
;
if
(
request
.
query
().
values
().
size
()
>
0
)
if
(
request
.
query
().
values
().
size
()
>
0
)
{
regionData
=
regions
.
get
(
regionName
).
getBase64
();
var
region
=
regions
.
get
(
regionName
);
if
(
region
!=
null
)
regionData
=
region
.
getBase64
();
}
// Invoke event.
// Invoke event.
QueryCurrentRegionEvent
event
=
new
QueryCurrentRegionEvent
(
regionData
);
event
.
call
();
QueryCurrentRegionEvent
event
=
new
QueryCurrentRegionEvent
(
regionData
);
event
.
call
();
...
@@ -183,4 +185,12 @@ public final class RegionHandler implements Router {
...
@@ -183,4 +185,12 @@ public final class RegionHandler implements Router {
return
this
.
base64
;
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
;
}
}
}
src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java
View file @
3adf0d44
package
emu.grasscutter.server.http.handlers
;
package
emu.grasscutter.server.http.handlers
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.server.
dispatch.DispatchHttpJsonHandler
;
import
emu.grasscutter.server.
http.objects.HttpJsonResponse
;
import
emu.grasscutter.server.http.Router
;
import
emu.grasscutter.server.http.Router
;
import
express.Express
;
import
express.Express
;
import
express.http.Request
;
import
express.http.Request
;
...
@@ -21,15 +21,15 @@ import static emu.grasscutter.Configuration.DATA;
...
@@ -21,15 +21,15 @@ import static emu.grasscutter.Configuration.DATA;
public
final
class
AnnouncementsHandler
implements
Router
{
public
final
class
AnnouncementsHandler
implements
Router
{
@Override
public
void
applyRoutes
(
Express
express
,
Javalin
handle
)
{
@Override
public
void
applyRoutes
(
Express
express
,
Javalin
handle
)
{
// hk4e-api-os.hoyoverse.com
// hk4e-api-os.hoyoverse.com
express
.
all
(
"/common/hk4e_global/announcement/api/getAlertPic"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"total\":0,\"list\":[]}}"
));
express
.
all
(
"/common/hk4e_global/announcement/api/getAlertPic"
,
new
HttpJsonResponse
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"total\":0,\"list\":[]}}"
));
// hk4e-api-os.hoyoverse.com
// hk4e-api-os.hoyoverse.com
express
.
all
(
"/common/hk4e_global/announcement/api/getAlertAnn"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"alert\":false,\"alert_id\":0,\"remind\":true}}"
));
express
.
all
(
"/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
// hk4e-api-os.hoyoverse.com
express
.
all
(
"/common/hk4e_global/announcement/api/getAnnList"
,
AnnouncementsHandler:
:
getAnnouncement
);
express
.
all
(
"/common/hk4e_global/announcement/api/getAnnList"
,
AnnouncementsHandler:
:
getAnnouncement
);
// hk4e-api-os-static.hoyoverse.com
// hk4e-api-os-static.hoyoverse.com
express
.
all
(
"/common/hk4e_global/announcement/api/getAnnContent"
,
AnnouncementsHandler:
:
getAnnouncement
);
express
.
all
(
"/common/hk4e_global/announcement/api/getAnnContent"
,
AnnouncementsHandler:
:
getAnnouncement
);
// hk4e-sdk-os.hoyoverse.com
// hk4e-sdk-os.hoyoverse.com
express
.
all
(
"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier"
,
new
DispatchHttpJsonHandler
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}"
));
express
.
all
(
"/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier"
,
new
HttpJsonResponse
(
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"suggest_currency\":\"USD\",\"tiers\":[]}}"
));
}
}
private
static
void
getAnnouncement
(
Request
request
,
Response
response
)
{
private
static
void
getAnnouncement
(
Request
request
,
Response
response
)
{
...
...
src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java
0 → 100644
View file @
3adf0d44
package
emu.grasscutter.server.http.handlers
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.server.http.Router
;
import
emu.grasscutter.tools.Tools
;
import
emu.grasscutter.utils.FileUtils
;
import
emu.grasscutter.utils.Utils
;
import
express.Express
;
import
express.http.Request
;
import
express.http.Response
;
import
io.javalin.Javalin
;
import
io.javalin.http.staticfiles.Location
;
import
java.io.File
;
import
static
emu
.
grasscutter
.
Configuration
.
DATA
;
/**
* Handles all gacha-related HTTP requests.
*/
public
final
class
GachaHandler
implements
Router
{
private
final
String
gachaMappings
;
private
static
String
frontendTemplate
=
"{{REPLACE_RECORD}}"
;
public
GachaHandler
()
{
this
.
gachaMappings
=
Utils
.
toFilePath
(
DATA
(
"/gacha_mappings.js"
));
if
(!(
new
File
(
this
.
gachaMappings
).
exists
()))
{
try
{
Tools
.
createGachaMapping
(
this
.
gachaMappings
);
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to create gacha mappings."
,
exception
);
}
}
var
templateFile
=
new
File
(
DATA
(
"/gacha_records.html"
));
if
(
templateFile
.
exists
())
frontendTemplate
=
new
String
(
FileUtils
.
read
(
templateFile
));
}
@Override
public
void
applyRoutes
(
Express
express
,
Javalin
handle
)
{
express
.
get
(
"/gacha"
,
GachaHandler:
:
gachaRecords
);
express
.
useStaticFallback
(
"/gacha/mappings"
,
this
.
gachaMappings
,
Location
.
EXTERNAL
);
}
private
static
void
gachaRecords
(
Request
request
,
Response
response
)
{
var
sessionKey
=
request
.
query
(
"s"
);
int
page
=
0
,
gachaType
=
0
;
if
(
request
.
query
(
"p"
)
!=
null
)
page
=
Integer
.
parseInt
(
request
.
query
(
"p"
));
if
(
request
.
query
(
"gachaType"
)
!=
null
)
gachaType
=
Integer
.
parseInt
(
request
.
query
(
"gachaType"
));
// Get account from session key.
var
account
=
DatabaseHelper
.
getAccountBySessionKey
(
sessionKey
);
if
(
account
==
null
)
// Send response.
response
.
status
(
404
).
send
(
"Unable to find account."
);
else
{
String
records
=
DatabaseHelper
.
getGachaRecords
(
account
.
getPlayerUid
(),
gachaType
,
page
).
toString
();
long
maxPage
=
DatabaseHelper
.
getGachaRecordsMaxPage
(
account
.
getPlayerUid
(),
page
,
gachaType
);
response
.
send
(
frontendTemplate
.
replace
(
"{{REPLACE_RECORD}}"
,
records
)
.
replace
(
"{{REPLACE_MAXPAGE}}"
,
String
.
valueOf
(
maxPage
)));
}
}
}
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment