[+] Wacca user/status/login

pull/29/head
Azalea 2024-03-28 03:37:14 -04:00
parent 39d62099df
commit 00c5edcea7
6 changed files with 71 additions and 28 deletions

View File

@ -111,6 +111,10 @@ fun Str.asDateTime() = try { LocalDateTime.parse(this, DateTimeFormatter.ISO_LOC
catch (e: Exception) { try { LocalDateTime.parse(this, ALT_DATETIME_FORMAT) }
catch (e: Exception) { null } }
val Calendar.year get() = get(Calendar.YEAR)
val Calendar.month get() = get(Calendar.MONTH) + 1
val Calendar.day get() = get(Calendar.DAY_OF_MONTH)
// Encodings
fun Long.toHex(len: Int = 16): Str = "0x${this.toString(len).padStart(len, '0').uppercase()}"
fun Map<String, Any>.toUrl() = entries.joinToString("&") { (k, v) -> "$k=$v" }

View File

@ -41,6 +41,17 @@ inline fun <reified T> Str.parseJackson() = if (contains("null")) {
else JACKSON.readValue(this, T::class.java)
fun <T> T.toJson() = JACKSON.writeValueAsString(this)
inline fun <reified T> String.json() = try {
JACKSON.readValue(this, T::class.java)
}
catch (e: Exception) {
println("Failed to parse JSON: $this")
throw e
}
fun String.jsonMap(): Map<String, Any?> = json()
fun String.jsonArray(): List<Map<String, Any?>> = json()
// KotlinX Serialization
@OptIn(ExperimentalSerializationApi::class)

View File

@ -12,24 +12,25 @@ import io.ktor.client.utils.*
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
import java.util.*
val empty = emptyList<Any>()
@RestController
@API("/g/wacca/")
class WaccaServer(val rp: WaccaRepos, val cardRepo: CardRepository) {
val handlerMap = mutableMapOf<String, (BaseRequest, List<Any>) -> List<Any>>()
val handlerMap = mutableMapOf<String, (BaseRequest, List<Any>) -> Any>()
val cacheMap = mutableMapOf<String, String>()
val log = logger()
init { api() }
init { init() }
// DSL Functions
fun options(u: WaccaUser?) = u?.let { rp.option.findByUser(u).associate { it.optId to it.value } } ?: emptyMap()
operator fun Map<Int, Int>.get(type: WaccaOptionType) = getOrDefault(type.id, type.default)
operator fun String.minus(value: Any) = value
operator fun String.invoke(block: (BaseRequest, List<Any>) -> List<Any>) { handlerMap[this.lowercase()] = block }
operator fun String.invoke(block: (BaseRequest, List<Any>) -> Any) { handlerMap[this.lowercase()] = block }
infix fun String.cached(block: () -> Any) { cacheMap[this.lowercase()] = block().toJson() }
/** Convert "3.07.01.JPN.26935.S" into "3.7.1" */
@ -54,13 +55,18 @@ class WaccaServer(val rp: WaccaRepos, val cardRepo: CardRepository) {
if (path in cacheMap) return resp(cacheMap[path]!!)
if (path !in handlerMap) return resp("[]", 1, "Not Found")
log.info("Wacca $path < $body")
val br = JACKSON.parse<BaseRequest>(body)
val resp = handlerMap[path]!!(br, br.params)
return resp(resp.toJson())
return handlerMap[path]!!(br, br.params).let { when (it) {
is String -> return resp(it)
is List<*> -> return resp(it.toJson())
else -> Error("Invalid response type ${it.javaClass}")
} }.let { log.info("Wacca $path > $it") }
}
}
fun WaccaServer.api() {
fun WaccaServer.init() {
"housing/get" cached { ls("housingId" - 39, "isNewCab" - 0) }
"housing/start" cached { ls("regionId" - 1, "recommendSongList" - ls(1269, 1007, 1270, 1002, 1020, 1003, 1008,
1211, 1018, 1092, 1056, 32, 1260, 1230, 1258, 1251, 2212, 1264, 1125, 1037, 2001, 1272, 1126, 1119, 1104, 1070,
@ -90,7 +96,7 @@ fun WaccaServer.api() {
"user/status/create" { _, (uid, name) ->
val u = rp.user.save(WaccaUser().apply {
card = cardRepo.findByExtId(uid.long())() ?: (400 - "Card not found")
card = cardRepo.findByExtId(uid.long())() ?: (404 - "Card not found")
username = name.toString()
})
@ -107,4 +113,22 @@ fun WaccaServer.api() {
ls(u.lStatus())
}
"user/status/login" api@ { _, (uid) ->
if (uid == 0) return@api "[[], [], [], 0, [2077, 1, 1, 1, [], []], 0, []]"
val u = rp.user.findByCardExtId(uid.long()) ?: (404 - "User not found")
// Record login
u.loginCountConsec = u.loginCount++
if (millis() - u.lastLoginDate.time > 86400000) { // Is new day
u.loginCountDays++
u.loginCountToday = 0
if (millis() - u.lastLoginDate.time < 172800000) u.loginCountDaysConsec++
}
u.loginCountToday++
u.lastLoginDate = Date()
"[[], [], [], 0, [2077, 1, 1, 1, [], []], ${u.lastLoginDate.time / 1000}, []]"
}
}

View File

@ -51,7 +51,8 @@ class WaccaUser : BaseEntity() {
var lastFolderOrder = 0
var lastFolderId = 0
var lastSongOrder = 0
var lastLoginDate: String? = null
@Temporal(TemporalType.TIME)
var lastLoginDate: Date = Date(0)
var gateTutorialFlags: String? = null
fun lStatus() = ls(card.extId, username, 1, xp, danLevel, danType, wp, ls(0, 0, 0), loginCount, loginCountDays,

View File

@ -12,17 +12,6 @@ const val FTK = "test"
const val HOST = "http://localhost"
val ACCESS_CODE = "9900" + (1..16).map { Random.nextInt(0..9) }.joinToString("")
inline fun <reified T> String.json() = try {
JACKSON.readValue(this, T::class.java)
}
catch (e: Exception) {
println("Failed to parse JSON: $this")
throw e
}
fun String.jsonMap(): Map<String, Any?> = json()
fun String.jsonArray(): List<Map<String, Any?>> = json()
suspend fun registerUser(): Long {
val resp = HTTP.post(HOST.ensureEndingSlash() + "api/v2/frontier/register-card") {
parameter("ftk", FTK)

View File

@ -28,31 +28,45 @@ class WaccaTest : StringSpec({
return PostResp(resp, res["params"] as List<Any>)
}
infix fun List<Any?>.exp(expected: List<Any?>) {
expected.size shouldBe size
for (i in indices) {
val a = this[i]
when (val b = expected[i]) {
null -> {} // Use null to ignore the value
is List<*> -> a as List<Any> exp b as List<Any>
else -> a shouldBe b
}
}
}
infix fun List<Any?>.exp(json: String) = exp(json.jsonArray())
beforeTest {
if (uid == 0L) uid = registerUser()
}
"housing/get #1" {
post("housing/get", "[]").res shouldBe "[39, 0]".jsonArray()
post("housing/get", "[]").res exp "[39, 0]"
}
"housing/start #1" {
post("housing/start", """["", "2024/03/24 10:39:36, ApiUserStatusLogout,0\\n2024/03/24 10:51:06, ApiUserStatusLogout,0\\n2024/03/24 10:54:19, ApiUserStatusLogout,0\\n2024/03/24 10:59:33, ApiAdvertiseGetNews,0\\n2024/03/24 11:10:31, ApiAdvertiseGetNews,0\\n2024/03/24 11:11:04, ApiUserStatusLogout,0\\n2024/03/24 11:19:51, ,0\\n2024/03/24 11:20:14, ApiAdvertiseGetNews,0\\n", "", [[1, "SERVER"], [2, "JPN"]]]""").res shouldBe
"[1, [1269, 1007, 1270, 1002, 1020, 1003, 1008, 1211, 1018, 1092, 1056, 32, 1260, 1230, 1258, 1251, 2212, 1264, 1125, 1037, 2001, 1272, 1126, 1119, 1104, 1070, 1047, 1044, 1027, 1004, 1001, 24, 2068, 2062, 2021, 1275, 1249, 1207, 1203, 1107, 1021, 1009, 9, 4, 3, 23, 22, 2014, 13, 1276, 1247, 1240, 1237, 1128, 1114, 1110, 1109, 1102, 1045, 1043, 1036, 1035, 1030, 1023, 1015]]".jsonArray()
post("housing/start", """["", "2024/03/24 10:39:36, ApiUserStatusLogout,0\\n2024/03/24 10:51:06, ApiUserStatusLogout,0\\n2024/03/24 10:54:19, ApiUserStatusLogout,0\\n2024/03/24 10:59:33, ApiAdvertiseGetNews,0\\n2024/03/24 11:10:31, ApiAdvertiseGetNews,0\\n2024/03/24 11:11:04, ApiUserStatusLogout,0\\n2024/03/24 11:19:51, ,0\\n2024/03/24 11:20:14, ApiAdvertiseGetNews,0\\n", "", [[1, "SERVER"], [2, "JPN"]]]""").res exp
"[1, [1269, 1007, 1270, 1002, 1020, 1003, 1008, 1211, 1018, 1092, 1056, 32, 1260, 1230, 1258, 1251, 2212, 1264, 1125, 1037, 2001, 1272, 1126, 1119, 1104, 1070, 1047, 1044, 1027, 1004, 1001, 24, 2068, 2062, 2021, 1275, 1249, 1207, 1203, 1107, 1021, 1009, 9, 4, 3, 23, 22, 2014, 13, 1276, 1247, 1240, 1237, 1128, 1114, 1110, 1109, 1102, 1045, 1043, 1036, 1035, 1030, 1023, 1015]]"
}
"advertise/GetNews #1" {
post("advertise/GetNews", "[]").res shouldBe
"[[], [], [], [], [], [], [], [], []]".jsonArray()
post("advertise/GetNews", "[]").res exp
"[[], [], [], [], [], [], [], [], []]"
}
"user/status/get #1" {
post("user/status/get", """["$uid"]""").res shouldBe
"""[[0, "", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0], 104001, 102001, 1, [2, "1.0.0"], []]""".jsonArray()
post("user/status/get", """["$uid"]""").res exp
"""[[0, "", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0], 104001, 102001, 1, [2, "1.0.0"], []]"""
}
"user/status/create #1" {
post("user/status/create", """["$uid", "AZA"]""").res shouldBe
"""[[$uid, "AZA", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0]]""".jsonArray()
post("user/status/create", """["$uid", "AZA"]""").res exp
"""[[$uid, "AZA", 1, 0, 0, 0, 0, [0, 0, 0], 0, 0, 0, 0, 0, 0, 0]]"""
}
})