-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Removed submodules - No one used the libs anyways - Was making things unnecessary complicated * Remove weird import artifact * Still waiting for GitHub to allow delete caches. * Remove sourceSets * Not yet working * Cleanup error handling
- Loading branch information
1 parent
3d0452d
commit c8ca60a
Showing
206 changed files
with
2,351 additions
and
327 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
src/main/kotlin/com/lambda/client/capeapi/AbstractUUIDManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package com.lambda.client.capeapi | ||
|
||
import com.google.gson.GsonBuilder | ||
import com.google.gson.JsonParser | ||
import com.google.gson.reflect.TypeToken | ||
import com.lambda.client.commons.extension.synchronized | ||
import com.lambda.client.commons.utils.ConnectionUtils | ||
import org.apache.logging.log4j.Logger | ||
import java.io.File | ||
import java.io.FileWriter | ||
import java.util.* | ||
|
||
abstract class AbstractUUIDManager( | ||
filePath: String, | ||
private val logger: Logger, | ||
private val maxCacheSize: Int = 500 | ||
) { | ||
|
||
private val file = File(filePath) | ||
|
||
@Suppress("DEPRECATION") | ||
private val parser = JsonParser() | ||
private val gson = GsonBuilder().setPrettyPrinting().create() | ||
private val type = TypeToken.getArray(PlayerProfile::class.java).type | ||
|
||
private val nameProfileMap = LinkedHashMap<String, PlayerProfile>().synchronized() | ||
private val uuidNameMap = LinkedHashMap<UUID, PlayerProfile>().synchronized() | ||
|
||
fun getByString(stringIn: String?) = stringIn?.let { string -> | ||
UUIDUtils.fixUUID(string)?.let { getByUUID(it) } ?: getByName(string) | ||
} | ||
|
||
fun getByUUID(uuid: UUID?) = uuid?.let { | ||
uuidNameMap.getOrPut(uuid) { | ||
getOrRequest(uuid.toString())?.also { profile -> | ||
// If UUID already present in nameUuidMap but not in uuidNameMap (user changed name) | ||
nameProfileMap[profile.name]?.let { uuidNameMap.remove(it.uuid) } | ||
nameProfileMap[profile.name] = profile | ||
} ?: return null | ||
}.also { | ||
trimMaps() | ||
} | ||
} | ||
|
||
fun getByName(name: String?) = name?.let { | ||
nameProfileMap.getOrPut(name.lowercase()) { | ||
getOrRequest(name)?.also { profile -> | ||
// If UUID already present in uuidNameMap but not in nameUuidMap (user changed name) | ||
uuidNameMap[profile.uuid]?.let { nameProfileMap.remove(it.name) } | ||
uuidNameMap[profile.uuid] = profile | ||
} ?: return null | ||
}.also { | ||
trimMaps() | ||
} | ||
} | ||
|
||
private fun trimMaps() { | ||
while (nameProfileMap.size > maxCacheSize) { | ||
nameProfileMap.remove(nameProfileMap.keys.first())?.also { | ||
uuidNameMap.remove(it.uuid) | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Overwrites this if you want to get UUID from other source | ||
* eg. online player in game client | ||
*/ | ||
protected open fun getOrRequest(nameOrUUID: String): PlayerProfile? { | ||
return requestProfile(nameOrUUID) | ||
} | ||
|
||
private fun requestProfile(nameOrUUID: String): PlayerProfile? { | ||
val isUUID = UUIDUtils.isUUID(nameOrUUID) | ||
val response = if (isUUID) requestProfileFromUUID(nameOrUUID) else requestProfileFromName(nameOrUUID) | ||
|
||
return if (response.isNullOrBlank()) { | ||
logger.error("Response is null or blank, internet might be down") | ||
null | ||
} else { | ||
try { | ||
@Suppress("DEPRECATION") val jsonElement = parser.parse(response) | ||
if (isUUID) { | ||
val name = jsonElement.asJsonArray.last().asJsonObject["name"].asString | ||
PlayerProfile(UUID.fromString(nameOrUUID), name) | ||
} else { | ||
val id = jsonElement.asJsonObject["id"].asString | ||
val name = jsonElement.asJsonObject["name"].asString | ||
PlayerProfile(UUIDUtils.fixUUID(id)!!, name) // let it throw a NPE if failed to parse the string to UUID | ||
} | ||
} catch (e: Exception) { | ||
logger.error("Failed parsing profile", e) | ||
null | ||
} | ||
} | ||
} | ||
|
||
private fun requestProfileFromUUID(uuid: String): String? { | ||
return request("https://api.mojang.com/user/profiles/${UUIDUtils.removeDashes(uuid)}/names") | ||
} | ||
|
||
private fun requestProfileFromName(name: String): String? { | ||
return request("https://api.mojang.com/users/profiles/minecraft/$name") | ||
} | ||
|
||
private fun request(url: String): String? { | ||
return ConnectionUtils.requestRawJsonFrom(url) { | ||
logger.error("Failed requesting from Mojang API", it) | ||
} | ||
} | ||
|
||
fun load(): Boolean { | ||
fixEmptyJson(file) | ||
return try { | ||
val cacheList = file.bufferedReader().use { | ||
gson.fromJson<Array<PlayerProfile>>(it, type) | ||
} | ||
uuidNameMap.clear() | ||
nameProfileMap.clear() | ||
uuidNameMap.putAll(cacheList.associateBy { it.uuid }) | ||
nameProfileMap.putAll(cacheList.associateBy { it.name.lowercase() }) | ||
logger.info("UUID cache loaded") | ||
true | ||
} catch (e: Exception) { | ||
logger.warn("Failed loading UUID cache", e) | ||
false | ||
} | ||
} | ||
|
||
fun save(): Boolean { | ||
return try { | ||
val cacheList = uuidNameMap.values.sortedBy { it.name } | ||
file.bufferedWriter().use { | ||
gson.toJson(cacheList, it) | ||
} | ||
logger.info("UUID cache saved") | ||
true | ||
} catch (e: Exception) { | ||
logger.warn("Failed saving UUID cache", e) | ||
false | ||
} | ||
} | ||
|
||
private fun fixEmptyJson(file: File) { | ||
if (!file.exists()) file.createNewFile() | ||
var notEmpty = false | ||
file.forEachLine { notEmpty = notEmpty || it.trim().isNotBlank() || it == "[]" || it == "{}" } | ||
|
||
if (!notEmpty) { | ||
val fileWriter = FileWriter(file) | ||
try { | ||
fileWriter.write("[]") | ||
} catch (e: Exception) { | ||
logger.error("Failed to fix empty json", e) | ||
} finally { | ||
fileWriter.close() | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.lambda.client.capeapi | ||
|
||
import com.google.gson.annotations.SerializedName | ||
import java.util.* | ||
|
||
data class CapeUser( | ||
val id: Long, | ||
val capes: ArrayList<Cape>, | ||
@SerializedName("is_premium") | ||
var isPremium: Boolean = false | ||
) { | ||
override fun equals(other: Any?): Boolean { | ||
return this === other | ||
|| other is CapeUser | ||
&& other.id == this.id | ||
&& other.capes == capes | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return 31 * id.hashCode() + capes.hashCode() | ||
} | ||
} | ||
|
||
data class Cape( | ||
@SerializedName("cape_uuid") | ||
val capeUUID: String = UUID.randomUUID().toString().substring(0, 5), | ||
@SerializedName("player_uuid") | ||
var playerUUID: UUID? = null, | ||
val type: CapeType, | ||
var color: CapeColor = type.color | ||
) { | ||
override fun equals(other: Any?): Boolean { | ||
return this === other | ||
|| other is Cape | ||
&& other.capeUUID == capeUUID | ||
&& other.type == other.type | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return 31 * capeUUID.hashCode() + type.hashCode() | ||
} | ||
} | ||
|
||
data class CapeColor( | ||
val primary: String, | ||
val border: String | ||
) { | ||
override fun toString(): String { | ||
return "#$primary, #$border" | ||
} | ||
} | ||
|
||
data class PlayerProfile( | ||
@SerializedName("uuid", alternate = ["UUID"]) | ||
val uuid: UUID, | ||
@SerializedName("name", alternate = ["Name"]) | ||
val name: String | ||
) { | ||
override fun equals(other: Any?): Boolean { | ||
return this === other | ||
|| other is PlayerProfile | ||
&& other.uuid == uuid | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return uuid.hashCode() | ||
} | ||
} | ||
|
||
enum class CapeType(val realName: String, val imageKey: String, val color: CapeColor) { | ||
CONTRIBUTOR("Contributor", "github", CapeColor("272727", "363636")) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.lambda.client.capeapi | ||
|
||
import java.util.* | ||
|
||
object UUIDUtils { | ||
private val uuidRegex = "[a-z0-9].{7}-[a-z0-9].{3}-[a-z0-9].{3}-[a-z0-9].{3}-[a-z0-9].{11}".toRegex() | ||
|
||
fun fixUUID(string: String): UUID? { | ||
if (isUUID(string)) return UUID.fromString(string) | ||
if (string.length < 32) return null | ||
val fixed = insertDashes(string) | ||
return if (isUUID(fixed)) UUID.fromString(fixed) | ||
else null | ||
} | ||
|
||
fun isUUID(string: String) = uuidRegex.matches(string) | ||
|
||
fun removeDashes(string: String) = string.replace("-", "") | ||
|
||
private fun insertDashes(string: String) = StringBuilder(string) | ||
.insert(8, '-') | ||
.insert(13, '-') | ||
.insert(18, '-') | ||
.insert(23, '-') | ||
.toString() | ||
} |
Oops, something went wrong.