mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-18 18:40:34 +08:00
nothing
This commit is contained in:
parent
d2529cfc23
commit
d8be9abcc5
@ -17,14 +17,24 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth
|
||||
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile
|
||||
import org.jackhuang.hmcl.util.Immutable
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter
|
||||
|
||||
@Immutable
|
||||
data class AuthInfo(
|
||||
data class AuthInfo @JvmOverloads constructor(
|
||||
val username: String,
|
||||
val userId: String,
|
||||
val authToken: String,
|
||||
val userType: UserType = UserType.LEGACY,
|
||||
val userProperties: String = "{}",
|
||||
val userPropertyMap: String = "{}"
|
||||
)
|
||||
) {
|
||||
constructor(profile: GameProfile,
|
||||
authToken: String,
|
||||
userType: UserType = UserType.LEGACY,
|
||||
userProperties: String = "{}",
|
||||
userPropertyMap: String = "{}")
|
||||
: this(profile.name!!, UUIDTypeAdapter.fromUUID(profile.id!!), authToken, userType, userProperties, userPropertyMap) {
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil
|
||||
|
||||
data class AuthenticationRequest(
|
||||
data class AuthenticationRequest @JvmOverloads constructor(
|
||||
val username: String,
|
||||
val password: String,
|
||||
val clientToken: String,
|
||||
|
@ -21,7 +21,7 @@ import com.google.gson.*
|
||||
import java.lang.reflect.Type
|
||||
import java.util.*
|
||||
|
||||
data class GameProfile(
|
||||
data class GameProfile @JvmOverloads constructor(
|
||||
val id: UUID? = null,
|
||||
val name: String? = null,
|
||||
val properties: PropertyMap = PropertyMap(),
|
||||
@ -40,7 +40,7 @@ data class GameProfile(
|
||||
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext): GameProfile {
|
||||
if (json !is JsonObject)
|
||||
throw JsonParseException("The json element is not a JsonObject.")
|
||||
val id = if (json.has("id")) context.deserialize<UUID>(json.get("id"), UUID::class.java) else null
|
||||
val id = if (json.has("id")) context.deserialize(json.get("id"), UUID::class.java) else null
|
||||
val name = if (json.has("name")) json.getAsJsonPrimitive("name").asString else null
|
||||
return GameProfile(id, name)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil
|
||||
|
||||
data class RefreshRequest(
|
||||
data class RefreshRequest @JvmOverloads constructor(
|
||||
val clientToken: String,
|
||||
val accessToken: String,
|
||||
val selectedProfile: GameProfile? = null,
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.yggdrasil
|
||||
|
||||
class Response (
|
||||
class Response @JvmOverloads constructor(
|
||||
val accessToken: String? = null,
|
||||
val clientToken: String? = null,
|
||||
val selectedProfile: GameProfile? = null,
|
||||
|
@ -20,7 +20,7 @@ package org.jackhuang.hmcl.auth.yggdrasil
|
||||
import com.google.gson.JsonParseException
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
|
||||
class User (
|
||||
class User @JvmOverloads constructor(
|
||||
val id: String = "",
|
||||
val properties: PropertyMap? = null
|
||||
) : Validation {
|
||||
|
@ -57,8 +57,7 @@ class YggdrasilAccount private constructor(override val username: String): Accou
|
||||
override fun logIn(proxy: Proxy): AuthInfo {
|
||||
if (canPlayOnline)
|
||||
return AuthInfo(
|
||||
username = selectedProfile!!.name!!,
|
||||
userId = UUIDTypeAdapter.fromUUID(selectedProfile!!.id!!),
|
||||
profile = selectedProfile!!,
|
||||
authToken = accessToken!!,
|
||||
userType = userType,
|
||||
userProperties = GSON.toJson(userProperties)
|
||||
@ -72,8 +71,7 @@ class YggdrasilAccount private constructor(override val username: String): Accou
|
||||
throw UnsupportedOperationException("Do not support multi-available-profiles account yet.")
|
||||
} else {
|
||||
return AuthInfo(
|
||||
username = selectedProfile!!.name!!,
|
||||
userId = UUIDTypeAdapter.fromUUID(selectedProfile!!.id!!),
|
||||
profile = selectedProfile!!,
|
||||
authToken = accessToken!!,
|
||||
userType = userType,
|
||||
userProperties = GSON.toJson(userProperties)
|
||||
@ -149,7 +147,7 @@ class YggdrasilAccount private constructor(override val username: String): Accou
|
||||
if (!profile.properties.isEmpty())
|
||||
result[STORAGE_KEY_PROFILE_PROPERTIES] = profile.properties.toList()
|
||||
}
|
||||
if (accessToken != null && accessToken!!.isNotBlank())
|
||||
if (!accessToken.isNullOrBlank())
|
||||
result[STORAGE_KEY_ACCESS_TOKEN] = accessToken!!
|
||||
|
||||
return result
|
||||
@ -163,7 +161,7 @@ class YggdrasilAccount private constructor(override val username: String): Accou
|
||||
|
||||
val response = GSON.fromJson<Response>(jsonResult) ?: return null
|
||||
|
||||
if (response.error?.isNotBlank() ?: false) {
|
||||
if (!response.error.isNullOrBlank()) {
|
||||
LOG.severe("Failed to log in, the auth server returned an error: " + response.error + ", message: " + response.errorMessage + ", cause: " + response.cause)
|
||||
if (response.errorMessage != null)
|
||||
if (response.errorMessage.contains("Invalid credentials"))
|
||||
@ -216,10 +214,8 @@ class YggdrasilAccount private constructor(override val username: String): Accou
|
||||
|
||||
fun randomToken() = UUIDTypeAdapter.fromUUID(UUID.randomUUID())
|
||||
|
||||
override fun fromUsername(username: String, password: String): YggdrasilAccount {
|
||||
val account = YggdrasilAccount(username)
|
||||
account.password = password
|
||||
return account
|
||||
override fun fromUsername(username: String, password: String) = YggdrasilAccount(username).apply {
|
||||
this.password = password
|
||||
}
|
||||
|
||||
override fun fromStorage(storage: Map<Any, Any>): YggdrasilAccount {
|
||||
|
@ -17,16 +17,10 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.download
|
||||
|
||||
import org.jackhuang.hmcl.game.GameRepository
|
||||
import java.net.Proxy
|
||||
|
||||
abstract class AbstractDependencyManager
|
||||
: DependencyManager {
|
||||
abstract val downloadProvider: DownloadProvider
|
||||
|
||||
fun getVersions(id: String, selfVersion: String) =
|
||||
downloadProvider.getVersionListById(id).getVersions(selfVersion)
|
||||
|
||||
override fun getVersionList(id: String): VersionList<*> {
|
||||
return downloadProvider.getVersionListById(id)
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList
|
||||
/**
|
||||
* @see {@link http://bmclapi2.bangbang93.com}
|
||||
*/
|
||||
object BMCLAPIDownloadProvider : DownloadProvider() {
|
||||
object BMCLAPIDownloadProvider : DownloadProvider {
|
||||
override val libraryBaseURL: String = "http://bmclapi2.bangbang93.com/libraries/"
|
||||
override val versionListURL: String = "http://bmclapi2.bangbang93.com/mc/game/version_manifest.json"
|
||||
override val versionBaseURL: String = "http://bmclapi2.bangbang93.com/versions/"
|
||||
|
@ -34,7 +34,7 @@ import java.net.Proxy
|
||||
/**
|
||||
* This class has no state.
|
||||
*/
|
||||
class DefaultDependencyManager(override val repository: DefaultGameRepository, override var downloadProvider: DownloadProvider, override val proxy: Proxy = Proxy.NO_PROXY)
|
||||
class DefaultDependencyManager @JvmOverloads constructor(override val repository: DefaultGameRepository, override var downloadProvider: DownloadProvider, override val proxy: Proxy = Proxy.NO_PROXY)
|
||||
: AbstractDependencyManager() {
|
||||
|
||||
override fun gameBuilder(): GameBuilder = DefaultGameBuilder(this)
|
||||
@ -48,17 +48,19 @@ class DefaultDependencyManager(override val repository: DefaultGameRepository, o
|
||||
return ParallelTask(*tasks)
|
||||
}
|
||||
|
||||
override fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task {
|
||||
if (libraryId == "forge")
|
||||
return ForgeInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
else if (libraryId == "liteloader")
|
||||
return LiteLoaderInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
else if (libraryId == "optifine")
|
||||
return OptiFineInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
else
|
||||
throw IllegalArgumentException("Library id $libraryId is unrecognized.")
|
||||
}
|
||||
override fun installLibraryAsync(gameVersion: String, version: Version, libraryId: String, libraryVersion: String): Task =
|
||||
when (libraryId) {
|
||||
"forge" ->
|
||||
ForgeInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
"liteloader" ->
|
||||
LiteLoaderInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
"optifine" ->
|
||||
OptiFineInstallTask(this, gameVersion, version, libraryVersion)
|
||||
.then { VersionJSONSaveTask(repository, it["version"]) }
|
||||
else ->
|
||||
throw IllegalArgumentException("Library id $libraryId is unrecognized.")
|
||||
}
|
||||
|
||||
}
|
@ -20,12 +20,12 @@ package org.jackhuang.hmcl.download
|
||||
/**
|
||||
* The service provider that provides Minecraft online file downloads.
|
||||
*/
|
||||
abstract class DownloadProvider {
|
||||
abstract val libraryBaseURL: String
|
||||
abstract val versionListURL: String
|
||||
abstract val versionBaseURL: String
|
||||
abstract val assetIndexBaseURL: String
|
||||
abstract val assetBaseURL: String
|
||||
interface DownloadProvider {
|
||||
val libraryBaseURL: String
|
||||
val versionListURL: String
|
||||
val versionBaseURL: String
|
||||
val assetIndexBaseURL: String
|
||||
val assetBaseURL: String
|
||||
|
||||
/**
|
||||
* Inject into original URL provided by Mojang and Forge.
|
||||
@ -36,12 +36,12 @@ abstract class DownloadProvider {
|
||||
* @param baseURL original URL provided by Mojang and Forge.
|
||||
* @return the URL that is equivalent to [baseURL], but belongs to your own service provider.
|
||||
*/
|
||||
abstract fun injectURL(baseURL: String): String
|
||||
fun injectURL(baseURL: String): String
|
||||
|
||||
/**
|
||||
* the specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine"
|
||||
* @param id the id of specific version list that this download provider provides. i.e. "forge", "liteloader", "game", "optifine"
|
||||
* @return the version list
|
||||
*/
|
||||
abstract fun getVersionListById(id: String): VersionList<*>
|
||||
fun getVersionListById(id: String): VersionList<*>
|
||||
}
|
@ -26,10 +26,10 @@ import java.util.*
|
||||
/**
|
||||
* @see {@link http://wiki.vg}
|
||||
*/
|
||||
object MojangDownloadProvider : DownloadProvider() {
|
||||
object MojangDownloadProvider : DownloadProvider {
|
||||
override val libraryBaseURL: String = "https://libraries.minecraft.net/"
|
||||
override val versionBaseURL: String = "http://s3.amazonaws.com/Minecraft.Download/versions/"
|
||||
override val versionListURL: String = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
|
||||
override val versionBaseURL: String = "http://s3.amazonaws.com/Minecraft.Download/versions/"
|
||||
override val assetIndexBaseURL: String = "http://s3.amazonaws.com/Minecraft.Download/indexes/"
|
||||
override val assetBaseURL: String = "http://resources.download.minecraft.net/"
|
||||
|
||||
|
@ -23,7 +23,7 @@ import org.jackhuang.hmcl.util.Immutable
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
|
||||
@Immutable
|
||||
internal class ForgeVersion (
|
||||
internal class ForgeVersion @JvmOverloads constructor(
|
||||
val branch: String? = null,
|
||||
val mcversion: String? = null,
|
||||
val jobver: String? = null,
|
||||
@ -40,7 +40,7 @@ internal class ForgeVersion (
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal class ForgeVersionRoot (
|
||||
internal class ForgeVersionRoot @JvmOverloads constructor(
|
||||
val artifact: String? = null,
|
||||
val webpath: String? = null,
|
||||
val adfly: String? = null,
|
||||
@ -58,7 +58,7 @@ internal class ForgeVersionRoot (
|
||||
}
|
||||
|
||||
@Immutable
|
||||
internal data class Install (
|
||||
internal data class Install @JvmOverloads constructor(
|
||||
val profileName: String? = null,
|
||||
val target: String? = null,
|
||||
val path: String? = null,
|
||||
@ -71,7 +71,7 @@ internal data class Install (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal data class InstallProfile (
|
||||
internal data class InstallProfile @JvmOverloads constructor(
|
||||
@SerializedName("install")
|
||||
val install: Install? = null,
|
||||
@SerializedName("versionInfo")
|
||||
|
@ -42,7 +42,7 @@ object ForgeVersionList : VersionList<Unit>() {
|
||||
for ((x, versions) in root.mcversion!!.entries) {
|
||||
val gameVersion = x.asVersion() ?: continue
|
||||
for (v in versions) {
|
||||
val version = root.number!!.get(v) ?: continue
|
||||
val version = root.number!![v] ?: continue
|
||||
var jar: String? = null
|
||||
for (file in version.files!!)
|
||||
if (file.getOrNull(1) == "installer") {
|
||||
|
@ -102,7 +102,7 @@ class GameAssetRefreshTask(private val dependencyManager: DefaultDependencyManag
|
||||
val index = GSON.fromJson<AssetIndex>(assetIndexFile.readText())
|
||||
val res = LinkedList<Pair<File, AssetObject>>()
|
||||
var progress = 0
|
||||
index?.objects?.entries?.forEach { (_, assetObject) ->
|
||||
index?.objects?.values?.forEach { assetObject ->
|
||||
res += Pair(dependencyManager.repository.getAssetObject(version.id, assetIndexInfo.id, assetObject), assetObject)
|
||||
updateProgress(++progress, index.objects.size)
|
||||
}
|
||||
@ -119,7 +119,7 @@ class GameAssetRefreshTask(private val dependencyManager: DefaultDependencyManag
|
||||
* @param dependencyManager the dependency manager that can provides proxy settings and [GameRepository]
|
||||
* @param version the **resolved** version
|
||||
*/
|
||||
class GameAssetDownloadTask(private val dependencyManager: DefaultDependencyManager, private val version: Version) : Task() {
|
||||
class GameAssetDownloadTask(private val dependencyManager: DefaultDependencyManager, version: Version) : Task() {
|
||||
private val refreshTask = GameAssetRefreshTask(dependencyManager, version)
|
||||
override val dependents = listOf(refreshTask)
|
||||
override val dependencies = LinkedList<Task>()
|
||||
|
@ -33,7 +33,7 @@ internal class GameRemoteLatestVersions(
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal class GameRemoteVersion(
|
||||
internal class GameRemoteVersion @JvmOverloads constructor(
|
||||
@SerializedName("id")
|
||||
val gameVersion: String = "",
|
||||
@SerializedName("time")
|
||||
|
@ -44,7 +44,7 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
|
||||
|
||||
init {
|
||||
if (!liteLoaderVersionList.loaded)
|
||||
dependents += LiteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider).then {
|
||||
dependents += liteLoaderVersionList.refreshAsync(dependencyManager.downloadProvider).then {
|
||||
remote = liteLoaderVersionList.getVersion(gameVersion, remoteVersion) ?: throw IllegalArgumentException("Remote LiteLoader version $gameVersion, $remoteVersion not found")
|
||||
null
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import org.jackhuang.hmcl.game.Library
|
||||
import org.jackhuang.hmcl.util.Immutable
|
||||
|
||||
@Immutable
|
||||
internal data class LiteLoaderVersionsMeta (
|
||||
internal data class LiteLoaderVersionsMeta @JvmOverloads constructor(
|
||||
@SerializedName("description")
|
||||
val description: String = "",
|
||||
@SerializedName("authors")
|
||||
@ -32,7 +32,7 @@ internal data class LiteLoaderVersionsMeta (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal data class LiteLoaderRepository (
|
||||
internal data class LiteLoaderRepository @JvmOverloads constructor(
|
||||
@SerializedName("stream")
|
||||
val stream: String = "",
|
||||
@SerializedName("type")
|
||||
@ -44,7 +44,7 @@ internal data class LiteLoaderRepository (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal class LiteLoaderVersion (
|
||||
internal class LiteLoaderVersion @JvmOverloads constructor(
|
||||
@SerializedName("tweakClass")
|
||||
val tweakClass: String = "",
|
||||
@SerializedName("file")
|
||||
@ -62,7 +62,7 @@ internal class LiteLoaderVersion (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal class LiteLoaderBranch (
|
||||
internal class LiteLoaderBranch @JvmOverloads constructor(
|
||||
@SerializedName("libraries")
|
||||
val libraries: Collection<Library> = emptyList(),
|
||||
@SerializedName("com.mumfrey:liteloader")
|
||||
@ -70,7 +70,7 @@ internal class LiteLoaderBranch (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal class LiteLoaderGameVersions (
|
||||
internal class LiteLoaderGameVersions @JvmOverloads constructor(
|
||||
@SerializedName("repo")
|
||||
val repo: LiteLoaderRepository? = null,
|
||||
@SerializedName("artefacts")
|
||||
@ -80,7 +80,7 @@ internal class LiteLoaderGameVersions (
|
||||
)
|
||||
|
||||
@Immutable
|
||||
internal class LiteLoaderVersionsRoot (
|
||||
internal class LiteLoaderVersionsRoot @JvmOverloads constructor(
|
||||
@SerializedName("versions")
|
||||
val versions: Map<String, LiteLoaderGameVersions> = emptyMap(),
|
||||
@SerializedName("meta")
|
||||
|
@ -18,4 +18,4 @@
|
||||
package org.jackhuang.hmcl.download.optifine
|
||||
|
||||
|
||||
object Opt
|
||||
object OptiFineDownloadFormatter
|
@ -19,7 +19,7 @@ package org.jackhuang.hmcl.download.optifine
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class OptiFineVersion (
|
||||
data class OptiFineVersion @JvmOverloads constructor(
|
||||
@SerializedName("dl")
|
||||
val downloadLink: String? = null,
|
||||
@SerializedName("ver")
|
||||
|
@ -48,15 +48,15 @@ object OptiFineVersionList : VersionList<Unit>() {
|
||||
val doc = db.parse(ByteArrayInputStream(html.toByteArray()))
|
||||
val r = doc.documentElement
|
||||
val tables = r.getElementsByTagName("table")
|
||||
for (i in 0..tables.length - 1) {
|
||||
for (i in 0 until tables.length) {
|
||||
val e = tables.item(i) as Element
|
||||
if ("downloadTable" == e.getAttribute("class")) {
|
||||
val tr = e.getElementsByTagName("tr")
|
||||
for (k in 0..tr.length - 1) {
|
||||
for (k in 0 until tr.length) {
|
||||
val downloadLine = (tr.item(k) as Element).getElementsByTagName("td")
|
||||
var url: String? = null
|
||||
var version: String? = null
|
||||
for (j in 0..downloadLine.length - 1) {
|
||||
for (j in 0 until downloadLine.length) {
|
||||
val td = downloadLine.item(j) as Element
|
||||
if (td.getAttribute("class")?.startsWith("downloadLineMirror") ?: false)
|
||||
url = (td.getElementsByTagName("a").item(0) as Element).getAttribute("href")
|
||||
|
@ -21,7 +21,7 @@ import org.jackhuang.hmcl.task.Scheduler
|
||||
import java.util.*
|
||||
|
||||
class EventBus {
|
||||
val events = HashMap<Class<*>, EventManager<*>>()
|
||||
private val events = HashMap<Class<*>, EventManager<*>>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : EventObject> channel(classOfT: Class<T>): EventManager<T> {
|
||||
|
@ -21,7 +21,7 @@ import org.jackhuang.hmcl.task.Scheduler
|
||||
import org.jackhuang.hmcl.util.SimpleMultimap
|
||||
import java.util.*
|
||||
|
||||
class EventManager<T : EventObject>(val scheduler: Scheduler = Scheduler.IMMEDIATE) {
|
||||
class EventManager<T : EventObject> @JvmOverloads constructor(val scheduler: Scheduler = Scheduler.IMMEDIATE) {
|
||||
private val handlers = SimpleMultimap<EventPriority, (T) -> Unit>({ EnumMap(EventPriority::class.java) }, ::HashSet)
|
||||
private val handlers2 = SimpleMultimap<EventPriority, () -> Unit>({ EnumMap(EventPriority::class.java) }, ::HashSet)
|
||||
|
||||
|
@ -22,20 +22,17 @@ import java.util.*
|
||||
|
||||
/**
|
||||
* This event gets fired when loading versions in a .minecraft folder.
|
||||
* <br></br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.api.HMCLApi.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.core.version.MinecraftVersionManager]
|
||||
* *
|
||||
* @param IMinecraftService .minecraft folder.
|
||||
* *
|
||||
* @author huangyuhui
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
*
|
||||
* @param source [org.jackhuang.hmcl.game.GameRepository]
|
||||
*/
|
||||
class RefreshingVersionsEvent(source: Any) : EventObject(source)
|
||||
|
||||
/**
|
||||
* This event gets fired when all the versions in .minecraft folder are loaded.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.api.HMCLApi#EVENT_BUS}
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.game.GameRepository]
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@ -43,9 +40,9 @@ class RefreshedVersionsEvent(source: Any) : EventObject(source)
|
||||
|
||||
/**
|
||||
* This event gets fired when a minecraft version has been loaded.
|
||||
* <br></br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.api.HMCLApi.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.core.version.MinecraftVersionManager]
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.game.GameRepository]
|
||||
* @param version the version id.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@ -54,29 +51,29 @@ class LoadedOneVersionEvent(source: Any, val version: String) : EventObject(sour
|
||||
/**
|
||||
* This event gets fired when a JavaProcess exited abnormally and the exit code is not zero.
|
||||
* <br></br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.api.HMCLApi.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.util.sys.JavaProcessMonitor]
|
||||
* @param JavaProcess The process that exited abnormally.
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.launch.ExitWaiter]
|
||||
* @param value The process that exited abnormally.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class JavaProcessExitedAbnormallyEvent(source: Any, val value: ManagedProcess) : EventObject(source)
|
||||
class ProcessExitedAbnormallyEvent(source: Any, val value: ManagedProcess) : EventObject(source)
|
||||
|
||||
/**
|
||||
* This event gets fired when minecraft process exited successfully and the exit code is 0.
|
||||
* <br></br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.api.HMCLApi.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.util.sys.JavaProcessMonitor]
|
||||
* @param JavaProcess minecraft process
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.launch.ExitWaiter]
|
||||
* @param value minecraft process
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class JavaProcessStoppedEvent(source: Any, val value: ManagedProcess) : EventObject(source)
|
||||
class ProcessStoppedEvent(source: Any, val value: ManagedProcess) : EventObject(source)
|
||||
|
||||
/**
|
||||
* This event gets fired when we launch the JVM and it got crashed.
|
||||
* <br></br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.api.HMCLApi.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.util.sys.JavaProcessMonitor]
|
||||
* @param JavaProcess the crashed process.
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* @param source [org.jackhuang.hmcl.launch.ExitWaiter]
|
||||
* @param value the crashed process.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
class JVMLaunchFailedEvent(source: Any, val value: ManagedProcess) : EventObject(source)
|
||||
|
@ -17,5 +17,4 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.event
|
||||
|
||||
open class FailedEvent<T>(source: Any, val failedTime: Int, var newResult: T) : Event(source) {
|
||||
}
|
||||
open class FailedEvent<T>(source: Any, val failedTime: Int, var newResult: T) : Event(source)
|
@ -20,7 +20,7 @@ package org.jackhuang.hmcl.game
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.util.*
|
||||
|
||||
class AssetIndex(
|
||||
class AssetIndex @JvmOverloads constructor(
|
||||
@SerializedName("virtual")
|
||||
val virtual: Boolean = false,
|
||||
objects: Map<String, AssetObject> = emptyMap()
|
||||
|
@ -20,7 +20,7 @@ package org.jackhuang.hmcl.game
|
||||
import org.jackhuang.hmcl.util.Immutable
|
||||
|
||||
@Immutable
|
||||
class AssetIndexInfo(
|
||||
class AssetIndexInfo @JvmOverloads constructor(
|
||||
url: String = "",
|
||||
sha1: String? = null,
|
||||
size: Int = 0,
|
||||
|
@ -19,7 +19,7 @@ package org.jackhuang.hmcl.game
|
||||
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
|
||||
data class AssetObject(
|
||||
data class AssetObject @JvmOverloads constructor(
|
||||
val hash: String = "",
|
||||
val size: Long = 0
|
||||
): Validation {
|
||||
|
@ -21,7 +21,7 @@ package org.jackhuang.hmcl.game
|
||||
* What's circle dependency?
|
||||
* When C inherits from B, and B inherits from something else, and finally inherits from C again.
|
||||
*/
|
||||
class CircleDependencyException : Exception {
|
||||
class CircleDependencyException : GameException {
|
||||
constructor() : super() {}
|
||||
constructor(message: String) : super(message) {}
|
||||
constructor(message: String, cause: Throwable) : super(message, cause) {}
|
||||
|
@ -24,7 +24,7 @@ import org.jackhuang.hmcl.util.ignoreThrowable
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@Immutable
|
||||
data class CompatibilityRule(
|
||||
data class CompatibilityRule @JvmOverloads constructor(
|
||||
val action: Action = CompatibilityRule.Action.ALLOW,
|
||||
val os: OSRestriction? = null,
|
||||
val features: Map<String, Boolean>? = null
|
||||
@ -33,8 +33,8 @@ data class CompatibilityRule(
|
||||
fun getAppliedAction(supportedFeatures: Map<String, Boolean>): Action? {
|
||||
if (os != null && !os.allow()) return null
|
||||
if (features != null) {
|
||||
features.entries.forEach {
|
||||
if (supportedFeatures[it.key] != it.value)
|
||||
features.entries.forEach { (key, value) ->
|
||||
if (supportedFeatures[key] != value)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -57,12 +57,16 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository {
|
||||
* {@inheritsDoc}
|
||||
* @return something like ".minecraft/versions/<version name>/<version name>-natives"
|
||||
*/
|
||||
override fun getNativeDirectory(id: String) = File(getVersionRoot(id), "$id-natives")
|
||||
override fun getVersionRoot(id: String) = File(baseDirectory, "versions/$id")
|
||||
open fun getVersionJson(id: String) = File(getVersionRoot(id), "$id.json")
|
||||
override fun getNativeDirectory(id: String) = getVersionRoot(id).resolve("$id-natives")
|
||||
override fun getVersionRoot(id: String) = baseDirectory.resolve("versions/$id")
|
||||
open fun getVersionJson(id: String) = getVersionRoot(id).resolve("$id.json")
|
||||
|
||||
@Throws(IOException::class, JsonSyntaxException::class)
|
||||
open fun readVersionJson(id: String): Version? = readVersionJson(getVersionJson(id))
|
||||
@Throws(IOException::class, JsonSyntaxException::class, VersionNotFoundException::class)
|
||||
|
||||
@Throws(IOException::class, JsonSyntaxException::class)
|
||||
open fun readVersionJson(file: File): Version? = GSON.fromJson<Version>(file.readText())
|
||||
|
||||
override fun renameVersion(from: String, to: String): Boolean {
|
||||
try {
|
||||
val fromVersion = getVersion(from)
|
||||
@ -87,6 +91,7 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
open fun removeVersionFromDisk(name: String): Boolean {
|
||||
val file = getVersionRoot(name)
|
||||
if (!file.exists())
|
||||
@ -153,7 +158,7 @@ open class DefaultGameRepository(var baseDirectory: File): GameRepository {
|
||||
override fun getActualAssetDirectory(version: String, assetId: String): File {
|
||||
try {
|
||||
return reconstructAssets(version, assetId)
|
||||
} catch (e: IOException) {
|
||||
} catch (e: Exception) {
|
||||
LOG.log(Level.SEVERE, "Unable to reconstruct asset directory", e)
|
||||
return getAssetDirectory(version, assetId)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import org.jackhuang.hmcl.util.Immutable
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
|
||||
@Immutable
|
||||
open class DownloadInfo(
|
||||
open class DownloadInfo @JvmOverloads constructor(
|
||||
@SerializedName("url")
|
||||
val url: String = "",
|
||||
@SerializedName("sha1")
|
||||
@ -38,7 +38,7 @@ open class DownloadInfo(
|
||||
}
|
||||
|
||||
@Immutable
|
||||
open class IdDownloadInfo(
|
||||
open class IdDownloadInfo @JvmOverloads constructor(
|
||||
url: String = "",
|
||||
sha1: String? = null,
|
||||
size: Int = 0,
|
||||
|
@ -20,13 +20,13 @@ package org.jackhuang.hmcl.game
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.util.*
|
||||
|
||||
class ExtractRules(exclude: List<String> = emptyList()) {
|
||||
class ExtractRules @JvmOverloads constructor(exclude: List<String> = emptyList()) {
|
||||
val exclude: List<String> get() = Collections.unmodifiableList(excludeImpl)
|
||||
|
||||
@SerializedName("exclude")
|
||||
private val excludeImpl: MutableList<String> = LinkedList(exclude)
|
||||
|
||||
fun shouldExtract(path: String): Boolean =
|
||||
exclude.filter { path.startsWith(it) }.isEmpty()
|
||||
exclude.none { path.startsWith(it) }
|
||||
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
|
||||
class GameException : Exception {
|
||||
open class GameException : Exception {
|
||||
constructor() : super() {}
|
||||
constructor(message: String) : super(message) {}
|
||||
constructor(message: String, cause: Throwable) : super(message, cause) {}
|
||||
|
@ -32,7 +32,7 @@ private fun lessThan32(b: ByteArray, startIndex: Int): Int {
|
||||
}
|
||||
|
||||
fun matchArray(a: ByteArray, b: ByteArray): Int {
|
||||
for (i in 0..a.size - b.size - 1) {
|
||||
for (i in 0 until a.size - b.size) {
|
||||
var j = 1
|
||||
for (k in b.indices) {
|
||||
if (b[k] == a[i + k])
|
||||
|
@ -23,7 +23,7 @@ import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
@Immutable
|
||||
class LibrariesDownloadInfo(
|
||||
class LibrariesDownloadInfo @JvmOverloads constructor(
|
||||
@SerializedName("artifact")
|
||||
val artifact: LibraryDownloadInfo? = null,
|
||||
classifier_: Map<String, LibraryDownloadInfo>? = null
|
||||
|
@ -24,11 +24,9 @@ import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* A class that describes a Minecraft dependency.
|
||||
*
|
||||
* @see LibraryDeserializer
|
||||
*/
|
||||
@Immutable
|
||||
open class Library(
|
||||
open class Library @JvmOverloads constructor(
|
||||
val groupId: String,
|
||||
val artifactId: String,
|
||||
val version: String,
|
||||
@ -100,6 +98,7 @@ open class Library(
|
||||
context.deserialize(jsonObject["natives"], typeOf<Map<OS, String>>()),
|
||||
context.deserialize(jsonObject["rules"], typeOf<List<CompatibilityRule>>()))
|
||||
}
|
||||
|
||||
override fun serialize(src: Library?, typeOfSrc: Type?, context: JsonSerializationContext): JsonElement {
|
||||
if (src == null) return JsonNull.INSTANCE
|
||||
val obj = JsonObject()
|
||||
|
@ -21,7 +21,7 @@ import com.google.gson.annotations.SerializedName
|
||||
import org.jackhuang.hmcl.util.Immutable
|
||||
|
||||
@Immutable
|
||||
class LibraryDownloadInfo(
|
||||
class LibraryDownloadInfo @JvmOverloads constructor(
|
||||
url: String = "",
|
||||
sha1: String? = null,
|
||||
size: Int = 0,
|
||||
|
@ -22,9 +22,9 @@ import org.jackhuang.hmcl.util.Immutable
|
||||
import org.jackhuang.hmcl.util.Validation
|
||||
|
||||
@Immutable
|
||||
class LoggingInfo(
|
||||
class LoggingInfo @JvmOverloads constructor(
|
||||
@SerializedName("file")
|
||||
val file: IdDownloadInfo = IdDownloadInfo(""),
|
||||
val file: IdDownloadInfo = IdDownloadInfo(),
|
||||
|
||||
@SerializedName("argument")
|
||||
val argument: String = "",
|
||||
|
@ -20,7 +20,7 @@ package org.jackhuang.hmcl.game
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class StringArgument(var argument: String) : Argument {
|
||||
class StringArgument(val argument: String) : Argument {
|
||||
|
||||
override fun toString(keys: Map<String, String>, features: Map<String, Boolean>): List<String> {
|
||||
var res = argument
|
||||
|
@ -23,7 +23,7 @@ import org.jackhuang.hmcl.util.*
|
||||
import java.util.*
|
||||
|
||||
@Immutable
|
||||
open class Version(
|
||||
open class Version @JvmOverloads constructor(
|
||||
@SerializedName("minecraftArguments")
|
||||
val minecraftArguments: String? = null,
|
||||
@SerializedName("arguments")
|
||||
@ -88,7 +88,7 @@ open class Version(
|
||||
val actualAssetIndex: AssetIndexInfo
|
||||
get() {
|
||||
val id = assets ?: "legacy"
|
||||
return assetIndex ?: AssetIndexInfo(id = id, url = "$DEFAULT_VERSION_DOWNLOAD_URL$id.json")
|
||||
return assetIndex ?: AssetIndexInfo(id = id, url = "$DEFAULT_INDEX_URL$id.json")
|
||||
}
|
||||
|
||||
fun appliesToCurrentEnvironment() = CompatibilityRule.appliesToCurrentEnvironment(compatibilityRules)
|
||||
@ -134,8 +134,9 @@ open class Version(
|
||||
arguments = Arguments.mergeArguments(parent.arguments, this.arguments),
|
||||
releaseTime = this.releaseTime,
|
||||
inheritsFrom = null,
|
||||
compatibilityRules = merge(this.compatibilityRules, parent.compatibilityRules),
|
||||
minecraftArguments = this.minecraftArguments ?: parent.minecraftArguments,
|
||||
minimumLauncherVersion = parent.minimumLauncherVersion
|
||||
minimumLauncherVersion = maxOf(minimumLauncherVersion, parent.minimumLauncherVersion)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game
|
||||
|
||||
class VersionNotFoundException : Exception {
|
||||
class VersionNotFoundException : GameException {
|
||||
constructor() : super() {}
|
||||
constructor(message: String) : super(message) {}
|
||||
constructor(message: String, cause: Throwable) : super(message, cause) {}
|
||||
|
@ -31,7 +31,7 @@ import kotlin.concurrent.thread
|
||||
* @param account The user account
|
||||
* @param options The launching configuration
|
||||
*/
|
||||
open class DefaultLauncher(repository: GameRepository, versionId: String, account: AuthInfo, options: LaunchOptions, listener: ProcessListener? = null, isDaemon: Boolean = true)
|
||||
open class DefaultLauncher @JvmOverloads constructor(repository: GameRepository, versionId: String, account: AuthInfo, options: LaunchOptions, listener: ProcessListener? = null, isDaemon: Boolean = true)
|
||||
: Launcher(repository, versionId, account, options, listener, isDaemon) {
|
||||
|
||||
protected val native: File by lazy { repository.getNativeDirectory(version.id) }
|
||||
@ -143,7 +143,7 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
||||
|
||||
val features = getFeatures()
|
||||
res.addAll(Arguments.parseArguments(version.arguments?.game ?: defaultGameArguments, configuration, features))
|
||||
res.addAll(Arguments.parseStringArguments(version.minecraftArguments?.tokenize()?.toList() ?: emptyList(), configuration))
|
||||
res.addAll(Arguments.parseStringArguments(version.minecraftArguments?.tokenize() ?: emptyList(), configuration))
|
||||
|
||||
// Optional Minecraft arguments
|
||||
if (options.height != null && options.height != 0 && options.width != null && options.width != 0) {
|
||||
|
@ -19,8 +19,8 @@ package org.jackhuang.hmcl.launch
|
||||
|
||||
import org.jackhuang.hmcl.event.EVENT_BUS
|
||||
import org.jackhuang.hmcl.event.JVMLaunchFailedEvent
|
||||
import org.jackhuang.hmcl.event.JavaProcessExitedAbnormallyEvent
|
||||
import org.jackhuang.hmcl.event.JavaProcessStoppedEvent
|
||||
import org.jackhuang.hmcl.event.ProcessExitedAbnormallyEvent
|
||||
import org.jackhuang.hmcl.event.ProcessStoppedEvent
|
||||
import org.jackhuang.hmcl.util.ManagedProcess
|
||||
import org.jackhuang.hmcl.util.containsOne
|
||||
import org.jackhuang.hmcl.util.guessLogLineError
|
||||
@ -34,13 +34,13 @@ internal class ExitWaiter(val process: ManagedProcess, val joins: Collection<Thr
|
||||
try {
|
||||
val exitCode = process.process.waitFor()
|
||||
|
||||
joins.forEach { it.join() }
|
||||
joins.forEach(Thread::join)
|
||||
|
||||
val errorLines = process.lines.filter(::guessLogLineError)
|
||||
val exitType: ProcessListener.ExitType
|
||||
// LaunchWrapper will catch the exception logged and will exit normally.
|
||||
if (exitCode != 0 || errorLines.containsOne("Unable to launch")) {
|
||||
EVENT_BUS.fireEvent(JavaProcessExitedAbnormallyEvent(this, process))
|
||||
EVENT_BUS.fireEvent(ProcessExitedAbnormallyEvent(this, process))
|
||||
exitType = ProcessListener.ExitType.APPLICATION_ERROR
|
||||
} else if (exitCode != 0 && errorLines.containsOne(
|
||||
"Could not create the Java Virtual Machine.",
|
||||
@ -52,7 +52,7 @@ internal class ExitWaiter(val process: ManagedProcess, val joins: Collection<Thr
|
||||
} else
|
||||
exitType = ProcessListener.ExitType.NORMAL
|
||||
|
||||
EVENT_BUS.fireEvent(JavaProcessStoppedEvent(this, process))
|
||||
EVENT_BUS.fireEvent(ProcessStoppedEvent(this, process))
|
||||
|
||||
watcher(exitCode, exitType)
|
||||
} catch (e: InterruptedException) {
|
||||
|
@ -24,7 +24,7 @@ import org.jackhuang.hmcl.game.Version
|
||||
import org.jackhuang.hmcl.util.ManagedProcess
|
||||
import java.io.File
|
||||
|
||||
abstract class Launcher(
|
||||
abstract class Launcher @JvmOverloads constructor(
|
||||
protected val repository: GameRepository,
|
||||
protected val versionId: String,
|
||||
protected val account: AuthInfo,
|
||||
|
@ -124,8 +124,8 @@ internal class Log4jHandler(private val callback: (String, Log4jLevel) -> Unit)
|
||||
}
|
||||
}
|
||||
|
||||
override fun characters(ch: CharArray?, start: Int, length: Int) {
|
||||
val line = String(ch!!, start, length)
|
||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||
val line = String(ch, start, length)
|
||||
if (line.trim { it <= ' ' }.isEmpty()) return
|
||||
if (readingMessage)
|
||||
message!!.append(line).append(OS.LINE_SEPARATOR)
|
||||
|
@ -58,7 +58,7 @@ class CurseForgeModpackManifest @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
class CurseForgeModpackManifestMinecraft (
|
||||
class CurseForgeModpackManifestMinecraft @JvmOverloads constructor(
|
||||
@SerializedName("version")
|
||||
val gameVersion: String = "",
|
||||
@SerializedName("modLoaders")
|
||||
@ -69,7 +69,7 @@ class CurseForgeModpackManifestMinecraft (
|
||||
}
|
||||
}
|
||||
|
||||
class CurseForgeModpackManifestModLoader (
|
||||
class CurseForgeModpackManifestModLoader @JvmOverloads constructor(
|
||||
@SerializedName("id")
|
||||
val id: String = "",
|
||||
@SerializedName("primary")
|
||||
@ -80,7 +80,7 @@ class CurseForgeModpackManifestModLoader (
|
||||
}
|
||||
}
|
||||
|
||||
class CurseForgeModpackManifestFile (
|
||||
class CurseForgeModpackManifestFile @JvmOverloads constructor(
|
||||
@SerializedName("projectID")
|
||||
val projectID: Int = 0,
|
||||
@SerializedName("fileID")
|
||||
@ -185,10 +185,10 @@ class CurseForgeModpackCompletionTask(dependencyManager: DependencyManager, vers
|
||||
val manifestFile = repository.getVersionRoot(version).resolve("manifest.json")
|
||||
if (!manifestFile.exists()) manifest = null
|
||||
else {
|
||||
manifest = GSON.fromJson<CurseForgeModpackManifest>(repository.getVersionRoot(version).resolve("manifest.json").readText())!!
|
||||
manifest = GSON.fromJson<CurseForgeModpackManifest>(manifestFile.readText())!!
|
||||
|
||||
// Because in China, the CurseForge is too difficult to visit.
|
||||
// So caching the file name is necessary.
|
||||
// Because in China, CurseForge is too difficult to visit,
|
||||
// caching the file name is necessary.
|
||||
for (f in manifest!!.files) {
|
||||
if (f.fileName.isBlank())
|
||||
dependents += task { f.fileName = f.url.detectFileName(proxy) }
|
||||
|
@ -22,7 +22,7 @@ import org.jackhuang.hmcl.util.getValue
|
||||
import org.jackhuang.hmcl.util.setValue
|
||||
import java.io.File
|
||||
|
||||
class ModInfo (
|
||||
class ModInfo @JvmOverloads constructor(
|
||||
var file: File,
|
||||
val name: String,
|
||||
val description: String = "",
|
||||
|
@ -24,7 +24,7 @@ import org.jackhuang.hmcl.util.AutoTypingMap
|
||||
*
|
||||
* @param pred the task that runs before [succ]
|
||||
* @param succ a callback that returns the task runs after [pred], [succ] will be executed asynchronously. You can do something that relies on the result of [pred].
|
||||
* @param reliant true if this task chain will be broken when task [pred] fails.
|
||||
* @param reliesOnDependents true if this task chain will be broken when task [pred] fails.
|
||||
*/
|
||||
internal class CoupleTask<P: Task>(pred: P, private val succ: (AutoTypingMap<String>) -> Task?, override val reliesOnDependents: Boolean) : Task() {
|
||||
override val hidden: Boolean = true
|
||||
|
@ -46,7 +46,7 @@ class FileDownloadTask @JvmOverloads constructor(val url: URL, val file: File, v
|
||||
/**
|
||||
* Once downloading fails, this event will be fired to gain the substitute URL.
|
||||
*/
|
||||
var onFailed = EventManager<FailedEvent<URL>>()
|
||||
val onFailed = EventManager<FailedEvent<URL>>()
|
||||
|
||||
private var rFile: RandomAccessFile? = null
|
||||
private var stream: InputStream? = null
|
||||
@ -81,7 +81,7 @@ class FileDownloadTask @JvmOverloads constructor(val url: URL, val file: File, v
|
||||
try {
|
||||
updateProgress(0.0)
|
||||
|
||||
val conn = url.createConnection(proxy)
|
||||
val conn = currentURL.createConnection(proxy)
|
||||
conn.connect()
|
||||
|
||||
if (conn.responseCode / 100 != 2)
|
||||
|
@ -56,9 +56,9 @@ class GetTask @JvmOverloads constructor(val url: URL, val encoding: Charset = Ch
|
||||
val len = input.read(buf)
|
||||
if (len == -1)
|
||||
break
|
||||
read += len
|
||||
|
||||
baos.write(buf, 0, len)
|
||||
read += len
|
||||
updateProgress(read, size)
|
||||
|
||||
if (Thread.currentThread().isInterrupted)
|
||||
|
@ -57,11 +57,13 @@ interface Scheduler {
|
||||
val e = wrapper.get()
|
||||
if (e != null) throw ExecutionException(e)
|
||||
}
|
||||
|
||||
override fun get() {
|
||||
latch.await()
|
||||
val e = wrapper.get()
|
||||
if (e != null) throw ExecutionException(e)
|
||||
}
|
||||
|
||||
override fun isDone() = latch.count == 0L
|
||||
override fun isCancelled() = false
|
||||
override fun cancel(mayInterruptIfRunning: Boolean) = false
|
||||
@ -117,19 +119,25 @@ interface Scheduler {
|
||||
* A scheduler that always create new threads to execute tasks.
|
||||
* For tasks that do not do heavy operations.
|
||||
*/
|
||||
val NEW_THREAD: Scheduler = SchedulerExecutorService(CACHED_EXECUTOR)
|
||||
val NEW_THREAD: Scheduler by lazy {
|
||||
SchedulerExecutorService(CACHED_EXECUTOR)
|
||||
}
|
||||
|
||||
/**
|
||||
* A scheduler that exclusively executes tasks that do I/O operations.
|
||||
* The number tasks that do I/O operations in the meantime cannot be larger then 6.
|
||||
*/
|
||||
val IO: Scheduler = SchedulerExecutorService(IO_EXECUTOR)
|
||||
val IO: Scheduler by lazy {
|
||||
SchedulerExecutorService(IO_EXECUTOR)
|
||||
}
|
||||
|
||||
/**
|
||||
* A scheduler that exclusively executes tasks that do computations.
|
||||
* The best way to do computations is an event queue.
|
||||
*/
|
||||
val COMPUTATION: Scheduler = SchedulerExecutorService(SINGLE_EXECUTOR)
|
||||
val COMPUTATION: Scheduler by lazy {
|
||||
SchedulerExecutorService(SINGLE_EXECUTOR)
|
||||
}
|
||||
|
||||
/**
|
||||
* The default scheduler for tasks to be executed.
|
||||
|
@ -35,6 +35,7 @@ class TaskExecutor(private val task: Task) {
|
||||
val totTask = AtomicInteger(0)
|
||||
val variables = AutoTypingMap<String>(mutableMapOf())
|
||||
var lastException: Exception? = null
|
||||
private set
|
||||
private val workerQueue = ConcurrentLinkedQueue<Future<*>>()
|
||||
|
||||
/**
|
||||
@ -151,7 +152,7 @@ class TaskExecutor(private val task: Task) {
|
||||
return flag
|
||||
}
|
||||
|
||||
private inner class Invoker(val task: Task, val latch: CountDownLatch, val boolean: AtomicBoolean): Callable<Unit> {
|
||||
private inner class Invoker(private val task: Task, private val latch: CountDownLatch, private val boolean: AtomicBoolean): Callable<Unit> {
|
||||
override fun call() {
|
||||
try {
|
||||
Thread.currentThread().name = task.title
|
||||
|
@ -28,7 +28,7 @@ class AutoTypingMap<K>(private val impl: MutableMap<K, Any>) {
|
||||
operator fun <V> get(key: K): V = impl[key] as V
|
||||
operator fun set(key: K, value: Any?) {
|
||||
if (value != null)
|
||||
impl.set(key, value)
|
||||
impl[key] = value
|
||||
}
|
||||
val values get() = impl.values
|
||||
val keys get() = impl.keys
|
||||
|
@ -151,7 +151,6 @@ fun File.uncompressTo(dest: File, subDirectory: String = "", callback: ((String)
|
||||
/**
|
||||
* Read the text content of a file in zip.
|
||||
*
|
||||
* @param f the zip file
|
||||
* @param name the location of the text in zip file, something like A/B/C/D.txt
|
||||
* @throws IOException if the file is not a valid zip file.
|
||||
* @return the content of given file.
|
||||
@ -167,7 +166,6 @@ fun File.readTextZipEntry(name: String): String {
|
||||
/**
|
||||
* Read the text content of a file in zip.
|
||||
*
|
||||
* @param f the zip file
|
||||
* @param location the location of the text in zip file, something like A/B/C/D.txt
|
||||
* @return the content of given file.
|
||||
*/
|
||||
|
@ -78,16 +78,16 @@ interface Validation {
|
||||
|
||||
object ValidationTypeAdapterFactory : TypeAdapterFactory {
|
||||
override fun <T : Any?> create(gson: Gson, type: TypeToken<T?>?): TypeAdapter<T?> {
|
||||
val delgate = gson.getDelegateAdapter(this, type)
|
||||
val delegate = gson.getDelegateAdapter(this, type)
|
||||
return object : TypeAdapter<T?>() {
|
||||
override fun write(out: JsonWriter?, value: T?) {
|
||||
if (value is Validation)
|
||||
value.validate()
|
||||
delgate.write(out, value)
|
||||
delegate.write(out, value)
|
||||
}
|
||||
|
||||
override fun read(reader: JsonReader?): T? {
|
||||
val value = delgate.read(reader)
|
||||
val value = delegate.read(reader)
|
||||
if (value is Validation)
|
||||
value.validate()
|
||||
return value
|
||||
@ -160,7 +160,7 @@ object DateTypeAdapter : JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
if (json !is JsonPrimitive) {
|
||||
throw JsonParseException("The date should be a string value")
|
||||
} else {
|
||||
val date = this.deserializeToDate(json.getAsString())
|
||||
val date = this.deserializeToDate(json.asString)
|
||||
if (typeOfT === Date::class.java) {
|
||||
return date
|
||||
} else {
|
||||
@ -170,23 +170,23 @@ object DateTypeAdapter : JsonSerializer<Date>, JsonDeserializer<Date> {
|
||||
}
|
||||
|
||||
override fun serialize(src: Date, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
|
||||
synchronized(this.enUsFormat) {
|
||||
synchronized(enUsFormat) {
|
||||
return JsonPrimitive(this.serializeToString(src))
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeToDate(string: String): Date {
|
||||
synchronized(this.enUsFormat) {
|
||||
synchronized(enUsFormat) {
|
||||
try {
|
||||
return this.enUsFormat.parse(string)
|
||||
return enUsFormat.parse(string)
|
||||
} catch (ex1: ParseException) {
|
||||
try {
|
||||
return this.iso8601Format.parse(string)
|
||||
return iso8601Format.parse(string)
|
||||
} catch (ex2: ParseException) {
|
||||
try {
|
||||
var cleaned = string.replace("Z", "+00:00")
|
||||
cleaned = cleaned.substring(0, 22) + cleaned.substring(23)
|
||||
return this.iso8601Format.parse(cleaned)
|
||||
return iso8601Format.parse(cleaned)
|
||||
} catch (e: Exception) {
|
||||
throw JsonSyntaxException("Invalid date: " + string, e)
|
||||
}
|
||||
|
@ -30,9 +30,7 @@ fun Closeable.closeQuietly() {
|
||||
|
||||
fun InputStream.readFully(): ByteArrayOutputStream {
|
||||
try {
|
||||
val ans = ByteArrayOutputStream()
|
||||
copyTo(ans)
|
||||
return ans
|
||||
return ByteArrayOutputStream().apply { copyTo(this) }
|
||||
} finally {
|
||||
this.closeQuietly()
|
||||
}
|
||||
|
@ -47,14 +47,14 @@ fun initHttps() {
|
||||
if (INIT_HTTPS)
|
||||
return
|
||||
INIT_HTTPS = true
|
||||
System.setProperty("https.protocols", "SSLv3,TLSv1");
|
||||
System.setProperty("https.protocols", "SSLv3,TLSv1")
|
||||
try {
|
||||
val c = SSLContext.getInstance("SSL");
|
||||
c.init(null, arrayOf(XTM), SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(c.getSocketFactory());
|
||||
val c = SSLContext.getInstance("SSL")
|
||||
c.init(null, arrayOf(XTM), SecureRandom())
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(c.socketFactory)
|
||||
} catch (e: GeneralSecurityException) {
|
||||
}
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(HNV);
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(HNV)
|
||||
}
|
||||
|
||||
var DEFAULT_USER_AGENT: () -> String = { RandomUserAgent.randomUserAgent }
|
||||
@ -144,7 +144,7 @@ fun URL.detectFileName(proxy: Proxy = Proxy.NO_PROXY): String {
|
||||
|
||||
fun HttpURLConnection.detectFileName(): String {
|
||||
val disposition = getHeaderField("Content-Disposition")
|
||||
if (disposition == null || disposition.indexOf("filename=") == -1) {
|
||||
if (disposition == null || !disposition.contains("filename=")) {
|
||||
val u = url.toString()
|
||||
return u.substringAfterLast('/')
|
||||
} else
|
||||
|
@ -23,8 +23,8 @@ import java.util.*
|
||||
* A simple implementation of Multimap.
|
||||
* Just a combination of map and set.
|
||||
*/
|
||||
class SimpleMultimap<K, V>(val maper: () -> MutableMap<K, Collection<V>>, val valuer: () -> MutableCollection<V>) {
|
||||
private val map = HashMap<K, MutableCollection<V>>()
|
||||
class SimpleMultimap<K, V>(mapper: () -> MutableMap<K, MutableCollection<V>>, private val valuer: () -> MutableCollection<V>) {
|
||||
private val map = mapper()
|
||||
private val valuesImpl: MutableCollection<V> = valuer()
|
||||
|
||||
val size = valuesImpl.size
|
||||
@ -35,7 +35,7 @@ class SimpleMultimap<K, V>(val maper: () -> MutableMap<K, Collection<V>>, val va
|
||||
val isEmpty: Boolean = size == 0
|
||||
val isNotEmpty: Boolean = size != 0
|
||||
|
||||
fun containsKey(key: K): Boolean = map.containsKey(key)
|
||||
fun containsKey(key: K): Boolean = map[key]?.isNotEmpty() ?: false
|
||||
operator fun get(key: K): Collection<V> = map.getOrPut(key, valuer)
|
||||
|
||||
fun put(key: K, value: V) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user