mirror of
https://github.com/InvertGeek/MixFile.git
synced 2026-06-09 16:07:42 +08:00
1.14.0
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@
|
||||
<meta content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"
|
||||
name="viewport"/>
|
||||
<title>MixFile</title>
|
||||
<script type="module" crossorigin src="/assets/index-DrT-F2ns.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DY6oNwSC.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Ub7aM_kp.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -21,11 +21,13 @@ import com.donut.mixfile.util.objects.UpdateChecker
|
||||
import com.donut.mixfile.util.showError
|
||||
import com.donut.mixfile.util.showErrorDialog
|
||||
import com.tencent.mmkv.MMKV
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
|
||||
val appScope by lazy { MainScope() }
|
||||
val appScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||
|
||||
lateinit var kv: MMKV
|
||||
|
||||
|
||||
@@ -104,10 +104,12 @@ abstract class MixFileServer(
|
||||
}
|
||||
install(StatusPages) {
|
||||
exception<Throwable> { call, cause ->
|
||||
call.respondText(
|
||||
"发生错误: ${cause.message} ${cause.stackTraceToString()}",
|
||||
status = HttpStatusCode.InternalServerError
|
||||
)
|
||||
if (!call.response.isCommitted){
|
||||
call.respondText(
|
||||
"发生错误: ${cause.message} ${cause.stackTraceToString()}",
|
||||
status = HttpStatusCode.InternalServerError
|
||||
)
|
||||
}
|
||||
onError(cause)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +41,12 @@ fun MixFileServer.getDownloadRoute(): RoutingHandler {
|
||||
call.respondText("解析文件失败", status = HttpStatusCode.InternalServerError)
|
||||
return@route
|
||||
}
|
||||
val mixFile = shareInfo.fetchMixFile(httpClient)
|
||||
if (mixFile == null) {
|
||||
|
||||
val mixFile = try {
|
||||
shareInfo.fetchMixFile(httpClient)
|
||||
} catch (e: Exception) {
|
||||
call.respondText(
|
||||
"解析文件索引失败",
|
||||
"解析文件索引失败: ${e.stackTraceToString()}",
|
||||
status = HttpStatusCode.InternalServerError
|
||||
)
|
||||
return@route
|
||||
|
||||
@@ -59,9 +59,7 @@ private val encodeMap = run {
|
||||
fun MixShareInfo.shareCode(useShortCode: Boolean): String {
|
||||
if (useShortCode) {
|
||||
return "mf://${encodeHex(this.toString())}${
|
||||
MixShareInfo.ENCODER.encode(
|
||||
this.url.hashMD5().copyOf(6)
|
||||
)
|
||||
this.toString().substring(0, 8)
|
||||
}"
|
||||
}
|
||||
return "mf://$this"
|
||||
|
||||
@@ -125,7 +125,7 @@ data class MixShareInfo(
|
||||
|
||||
fun contentType(): String = fileName.parseFileMimeType()
|
||||
|
||||
suspend fun fetchMixFile(client: HttpClient): MixFile? {
|
||||
suspend fun fetchMixFile(client: HttpClient): MixFile {
|
||||
val decryptedBytes = fetchFile(url, client = client)
|
||||
return MixFile.fromBytes(decryptedBytes)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
package com.donut.mixfile.util
|
||||
|
||||
import android.os.Handler
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.alibaba.fastjson2.into
|
||||
import com.alibaba.fastjson2.toJSONString
|
||||
import com.donut.mixfile.app
|
||||
import com.donut.mixfile.appScope
|
||||
import com.donut.mixfile.kv
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
fun <T> constructCachedMutableValue(
|
||||
value: T,
|
||||
key: String,
|
||||
setVal: (value: T) -> Unit,
|
||||
getVal: () -> T,
|
||||
) =
|
||||
object : CachedMutableValue<T>(value, key) {
|
||||
object : CachedMutableValue<T>(value) {
|
||||
override fun readCachedValue(): T {
|
||||
return getVal()
|
||||
}
|
||||
@@ -32,20 +35,18 @@ fun <T> constructCachedMutableValue(
|
||||
fun cachedMutableOf(value: String, key: String) =
|
||||
constructCachedMutableValue(
|
||||
value,
|
||||
key,
|
||||
{ kv.encode(key, it) },
|
||||
{ kv.decodeString(key, value)!! })
|
||||
|
||||
fun cachedMutableOf(value: Boolean, key: String) =
|
||||
constructCachedMutableValue(value, key, { kv.encode(key, it) }, { kv.decodeBool(key, value) })
|
||||
constructCachedMutableValue(value, { kv.encode(key, it) }, { kv.decodeBool(key, value) })
|
||||
|
||||
fun cachedMutableOf(value: Long, key: String) =
|
||||
constructCachedMutableValue(value, key, { kv.encode(key, it) }, { kv.decodeLong(key, value) })
|
||||
constructCachedMutableValue(value, { kv.encode(key, it) }, { kv.decodeLong(key, value) })
|
||||
|
||||
fun cachedMutableOf(value: Set<String>, key: String) =
|
||||
constructCachedMutableValue(
|
||||
value,
|
||||
key,
|
||||
{ kv.encode(key, it) },
|
||||
{ kv.decodeStringSet(key, value)!! },
|
||||
)
|
||||
@@ -54,7 +55,6 @@ fun cachedMutableOf(value: Set<String>, key: String) =
|
||||
inline fun <reified T, reified C : Iterable<T>> cachedMutableOf(value: C, key: String) =
|
||||
constructCachedMutableValue(
|
||||
value,
|
||||
key,
|
||||
{
|
||||
kv.encode(key, it.toJSONString())
|
||||
},
|
||||
@@ -71,37 +71,40 @@ inline fun <reified T, reified C : Iterable<T>> cachedMutableOf(value: C, key: S
|
||||
|
||||
abstract class CachedMutableValue<T>(
|
||||
value: T,
|
||||
private val key: String,
|
||||
) {
|
||||
var value by mutableStateOf(value)
|
||||
private var saveTask: Runnable? = null
|
||||
private var value by mutableStateOf(value)
|
||||
private var loaded = false
|
||||
private val mutex = Mutex()
|
||||
private var saveTask: Job? = null
|
||||
|
||||
abstract fun readCachedValue(): T
|
||||
|
||||
abstract fun writeCachedValue(value: T)
|
||||
|
||||
operator fun getValue(thisRef: Any?, property: Any?): T {
|
||||
if (!loaded) {
|
||||
value = readCachedValue()
|
||||
synchronized(this) {
|
||||
if (!loaded) {
|
||||
value = readCachedValue()
|
||||
loaded = true
|
||||
}
|
||||
return value
|
||||
}
|
||||
loaded = true
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
operator fun setValue(thisRef: Any?, property: Any?, value: T) {
|
||||
if (this.value == value) {
|
||||
return
|
||||
}
|
||||
this.value = value
|
||||
synchronized(key) {
|
||||
val handler = Handler(app.mainLooper)
|
||||
saveTask?.let { handler.removeCallbacks(it) }
|
||||
val task = Runnable {
|
||||
appScope.launch(Dispatchers.IO) {
|
||||
catchError {
|
||||
writeCachedValue(value)
|
||||
}
|
||||
saveTask?.cancel()
|
||||
saveTask = appScope.launch(Dispatchers.Main) {
|
||||
mutex.withLock {
|
||||
delay(100)
|
||||
withContext(Dispatchers.IO) {
|
||||
writeCachedValue(this@CachedMutableValue.value)
|
||||
}
|
||||
}
|
||||
saveTask = task
|
||||
handler.postDelayed(task, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +226,7 @@ fun debug(text: String?, tag: String = "test") {
|
||||
Log.d(tag, text ?: "null")
|
||||
}
|
||||
|
||||
inline fun catchError(tag: String = "", onError: () -> Unit = {}, block: () -> Unit) {
|
||||
inline fun catchError(tag: String = "", block: () -> Unit) {
|
||||
try {
|
||||
block()
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.donut.mixfile.appScope
|
||||
import com.donut.mixfile.currentActivity
|
||||
import com.donut.mixfile.server.core.utils.isNotNull
|
||||
@@ -125,7 +126,7 @@ fun TipText(content: String, onClick: () -> Unit = {}) {
|
||||
|
||||
@Composable
|
||||
fun OnResume(block: () -> Unit) {
|
||||
val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
val lifecycleObserver = remember {
|
||||
LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.donut.mixfile
|
||||
|
||||
import io.ktor.http.URLBuilder
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.launch
|
||||
import org.junit.Test
|
||||
import java.util.Date
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
//appScope.launch(Dispatchers.IO) {
|
||||
// repeat(100) {
|
||||
@@ -37,6 +41,8 @@ class ExampleUnitTest {
|
||||
val map = mapOf(1 to "aa", 2 to "bb")
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun main() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user