refactor: confine all Zipline parser service ops to Zipline thread
This commit is contained in:
+63
-15
@@ -18,11 +18,14 @@ import dev.msfjarvis.claw.parser.LobstersParserService
|
||||
import dev.msfjarvis.claw.parser.model.ParserSerializersModule
|
||||
import java.io.File
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlinx.coroutines.ExecutorCoroutineDispatcher
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okio.ByteString.Companion.decodeHex
|
||||
import okio.FileSystem
|
||||
@@ -34,9 +37,18 @@ class AndroidZiplineParserClient(
|
||||
private val httpClient: OkHttpClient,
|
||||
private val verifySignatures: Boolean,
|
||||
) : LobstersParserClient, AutoCloseable {
|
||||
private val ziplineThread = AtomicReference<Thread>()
|
||||
private val dispatcher: ExecutorCoroutineDispatcher =
|
||||
Executors.newSingleThreadExecutor { runnable ->
|
||||
Thread(null, runnable, "Claw-ZiplineParser", ZIPLINE_THREAD_STACK_SIZE_BYTES)
|
||||
Thread(
|
||||
null,
|
||||
{
|
||||
ziplineThread.set(Thread.currentThread())
|
||||
runnable.run()
|
||||
},
|
||||
"Claw-ZiplineParser",
|
||||
ZIPLINE_THREAD_STACK_SIZE_BYTES,
|
||||
)
|
||||
}
|
||||
.asCoroutineDispatcher()
|
||||
private val mutex = Mutex()
|
||||
@@ -53,7 +65,7 @@ class AndroidZiplineParserClient(
|
||||
override fun close() {
|
||||
loadedService?.close()
|
||||
loadedService = null
|
||||
loadedZipline?.close()
|
||||
loadedZipline?.let { zipline -> onZiplineThread { zipline.close() } }
|
||||
loadedZipline = null
|
||||
dispatcher.close()
|
||||
}
|
||||
@@ -95,23 +107,59 @@ class AndroidZiplineParserClient(
|
||||
manifestUrl
|
||||
}
|
||||
|
||||
return when (
|
||||
val result =
|
||||
loader.loadOnce(
|
||||
applicationName = "zipline-parser",
|
||||
freshnessChecker = freshnessChecker,
|
||||
manifestUrl = effectiveManifestUrl,
|
||||
serializersModule = ParserSerializersModule,
|
||||
)
|
||||
) {
|
||||
is LoadResult.Success -> {
|
||||
loadedZipline = result.zipline
|
||||
result.zipline.take("LobstersParserService")
|
||||
return withContext(dispatcher) {
|
||||
when (
|
||||
val result =
|
||||
loader.loadOnce(
|
||||
applicationName = "zipline-parser",
|
||||
freshnessChecker = freshnessChecker,
|
||||
manifestUrl = effectiveManifestUrl,
|
||||
serializersModule = ParserSerializersModule,
|
||||
)
|
||||
) {
|
||||
is LoadResult.Success -> {
|
||||
loadedZipline = result.zipline
|
||||
DispatcherConfinedLobstersParserService(
|
||||
result.zipline.take("LobstersParserService")
|
||||
)
|
||||
}
|
||||
is LoadResult.Failure -> throw result.exception
|
||||
}
|
||||
is LoadResult.Failure -> throw result.exception
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> onZiplineThread(block: () -> T): T {
|
||||
return if (Thread.currentThread() === ziplineThread.get()) {
|
||||
block()
|
||||
} else {
|
||||
runBlocking(dispatcher) { block() }
|
||||
}
|
||||
}
|
||||
|
||||
private inner class DispatcherConfinedLobstersParserService(
|
||||
private val delegate: LobstersParserService
|
||||
) : LobstersParserService {
|
||||
override fun parsePostsPage(html: String) = onZiplineThread { delegate.parsePostsPage(html) }
|
||||
|
||||
override fun parsePostDetails(html: String) = onZiplineThread {
|
||||
delegate.parsePostDetails(html)
|
||||
}
|
||||
|
||||
override fun parseUser(html: String) = onZiplineThread { delegate.parseUser(html) }
|
||||
|
||||
override fun parseTagsPage(html: String) = onZiplineThread { delegate.parseTagsPage(html) }
|
||||
|
||||
override fun parseSearchResults(html: String) = onZiplineThread {
|
||||
delegate.parseSearchResults(html)
|
||||
}
|
||||
|
||||
override fun parseCsrfToken(html: String) = onZiplineThread { delegate.parseCsrfToken(html) }
|
||||
|
||||
override fun parseReplyForm(html: String) = onZiplineThread { delegate.parseReplyForm(html) }
|
||||
|
||||
override fun close() = onZiplineThread { delegate.close() }
|
||||
}
|
||||
|
||||
private fun extractEmbeddedArtifacts() {
|
||||
val assets = context.assets
|
||||
val ziplineAssets = assets.list("zipline").orEmpty()
|
||||
|
||||
Reference in New Issue
Block a user