Use IO context for IO operations

This commit is contained in:
oSumAtrIX 2024-07-01 00:35:28 +02:00
parent e9d1c8fae0
commit 7f8f1ff589
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
3 changed files with 59 additions and 50 deletions

View File

@ -4,6 +4,8 @@ import app.revanced.api.configuration.repository.AnnouncementRepository.Attachme
import app.revanced.api.configuration.schema.APIAnnouncement import app.revanced.api.configuration.schema.APIAnnouncement
import app.revanced.api.configuration.schema.APIResponseAnnouncement import app.revanced.api.configuration.schema.APIResponseAnnouncement
import app.revanced.api.configuration.schema.APIResponseAnnouncementId import app.revanced.api.configuration.schema.APIResponseAnnouncementId
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.* import kotlinx.datetime.*
import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.IntEntityClass
@ -11,16 +13,18 @@ import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.kotlin.datetime.datetime import org.jetbrains.exposed.sql.kotlin.datetime.datetime
import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
internal class AnnouncementRepository(private val database: Database) { internal class AnnouncementRepository(private val database: Database) {
init { init {
transaction { runBlocking {
SchemaUtils.create(AnnouncementTable, AttachmentTable) transaction {
SchemaUtils.create(AnnouncementTable, AttachmentTable)
}
} }
} }
fun all() = transaction { suspend fun all() = transaction {
buildSet { buildSet {
AnnouncementEntity.all().forEach { announcement -> AnnouncementEntity.all().forEach { announcement ->
add(announcement.toApi()) add(announcement.toApi())
@ -28,7 +32,7 @@ internal class AnnouncementRepository(private val database: Database) {
} }
} }
fun all(channel: String) = transaction { suspend fun all(channel: String) = transaction {
buildSet { buildSet {
AnnouncementEntity.find { AnnouncementTable.channel eq channel }.forEach { announcement -> AnnouncementEntity.find { AnnouncementTable.channel eq channel }.forEach { announcement ->
add(announcement.toApi()) add(announcement.toApi())
@ -36,7 +40,7 @@ internal class AnnouncementRepository(private val database: Database) {
} }
} }
fun delete(id: Int) = transaction { suspend fun delete(id: Int) = transaction {
val announcement = AnnouncementEntity.findById(id) ?: return@transaction val announcement = AnnouncementEntity.findById(id) ?: return@transaction
announcement.delete() announcement.delete()
@ -44,27 +48,27 @@ internal class AnnouncementRepository(private val database: Database) {
// TODO: These are inefficient, but I'm not sure how to make them more efficient. // TODO: These are inefficient, but I'm not sure how to make them more efficient.
fun latest() = transaction { suspend fun latest() = transaction {
AnnouncementEntity.all().maxByOrNull { it.createdAt }?.toApi() AnnouncementEntity.all().maxByOrNull { it.createdAt }?.toApi()
} }
fun latest(channel: String) = transaction { suspend fun latest(channel: String) = transaction {
AnnouncementEntity.find { AnnouncementTable.channel eq channel }.maxByOrNull { it.createdAt }?.toApi() AnnouncementEntity.find { AnnouncementTable.channel eq channel }.maxByOrNull { it.createdAt }?.toApi()
} }
fun latestId() = transaction { suspend fun latestId() = transaction {
AnnouncementEntity.all().maxByOrNull { it.createdAt }?.id?.value?.let { AnnouncementEntity.all().maxByOrNull { it.createdAt }?.id?.value?.let {
APIResponseAnnouncementId(it) APIResponseAnnouncementId(it)
} }
} }
fun latestId(channel: String) = transaction { suspend fun latestId(channel: String) = transaction {
AnnouncementEntity.find { AnnouncementTable.channel eq channel }.maxByOrNull { it.createdAt }?.id?.value?.let { AnnouncementEntity.find { AnnouncementTable.channel eq channel }.maxByOrNull { it.createdAt }?.id?.value?.let {
APIResponseAnnouncementId(it) APIResponseAnnouncementId(it)
} }
} }
fun archive( suspend fun archive(
id: Int, id: Int,
archivedAt: LocalDateTime?, archivedAt: LocalDateTime?,
) = transaction { ) = transaction {
@ -73,13 +77,13 @@ internal class AnnouncementRepository(private val database: Database) {
} }
} }
fun unarchive(id: Int) = transaction { suspend fun unarchive(id: Int) = transaction {
AnnouncementEntity.findById(id)?.apply { AnnouncementEntity.findById(id)?.apply {
archivedAt = null archivedAt = null
} }
} }
fun new(new: APIAnnouncement) = transaction { suspend fun new(new: APIAnnouncement) = transaction {
AnnouncementEntity.new announcement@{ AnnouncementEntity.new announcement@{
author = new.author author = new.author
title = new.title title = new.title
@ -98,7 +102,7 @@ internal class AnnouncementRepository(private val database: Database) {
} }
} }
fun update(id: Int, new: APIAnnouncement) = transaction { suspend fun update(id: Int, new: APIAnnouncement) = transaction {
AnnouncementEntity.findById(id)?.apply { AnnouncementEntity.findById(id)?.apply {
author = new.author author = new.author
title = new.title title = new.title
@ -117,7 +121,8 @@ internal class AnnouncementRepository(private val database: Database) {
} }
} }
private fun <T> transaction(block: Transaction.() -> T) = transaction(database, block) private suspend fun <T> transaction(statement: Transaction.() -> T) =
newSuspendedTransaction(Dispatchers.IO, database, statement = statement)
private object AnnouncementTable : IntIdTable() { private object AnnouncementTable : IntIdTable() {
val author = varchar("author", 32).nullable() val author = varchar("author", 32).nullable()

View File

@ -8,28 +8,28 @@ import kotlinx.datetime.LocalDateTime
internal class AnnouncementService( internal class AnnouncementService(
private val announcementRepository: AnnouncementRepository, private val announcementRepository: AnnouncementRepository,
) { ) {
fun latestId(channel: String): APIResponseAnnouncementId? = announcementRepository.latestId(channel) suspend fun latestId(channel: String): APIResponseAnnouncementId? = announcementRepository.latestId(channel)
fun latestId(): APIResponseAnnouncementId? = announcementRepository.latestId() suspend fun latestId(): APIResponseAnnouncementId? = announcementRepository.latestId()
fun latest(channel: String) = announcementRepository.latest(channel) suspend fun latest(channel: String) = announcementRepository.latest(channel)
fun latest() = announcementRepository.latest() suspend fun latest() = announcementRepository.latest()
fun all(channel: String) = announcementRepository.all(channel) suspend fun all(channel: String) = announcementRepository.all(channel)
fun all() = announcementRepository.all() suspend fun all() = announcementRepository.all()
fun new(new: APIAnnouncement) { suspend fun new(new: APIAnnouncement) {
announcementRepository.new(new) announcementRepository.new(new)
} }
fun archive(id: Int, archivedAt: LocalDateTime?) { suspend fun archive(id: Int, archivedAt: LocalDateTime?) {
announcementRepository.archive(id, archivedAt) announcementRepository.archive(id, archivedAt)
} }
fun unarchive(id: Int) { suspend fun unarchive(id: Int) {
announcementRepository.unarchive(id) announcementRepository.unarchive(id)
} }
fun update(id: Int, new: APIAnnouncement) { suspend fun update(id: Int, new: APIAnnouncement) {
announcementRepository.update(id, new) announcementRepository.update(id, new)
} }
fun delete(id: Int) { suspend fun delete(id: Int) {
announcementRepository.delete(id) announcementRepository.delete(id)
} }
} }

View File

@ -8,6 +8,8 @@ import app.revanced.library.PatchUtils
import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchBundleLoader
import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Caffeine
import io.ktor.util.* import io.ktor.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.net.URL import java.net.URL
@ -73,36 +75,38 @@ internal class PatchesService(
configurationRepository.patches.repository, configurationRepository.patches.repository,
) )
return patchesListCache.get(patchesRelease.tag) { return withContext(Dispatchers.IO) {
val patchesDownloadUrl = patchesRelease.assets patchesListCache.get(patchesRelease.tag) {
.first(configurationRepository.patches.assetRegex).downloadUrl val patchesDownloadUrl = patchesRelease.assets
.first(configurationRepository.patches.assetRegex).downloadUrl
val signatureDownloadUrl = patchesRelease.assets val signatureDownloadUrl = patchesRelease.assets
.first(configurationRepository.patches.signatureAssetRegex).downloadUrl .first(configurationRepository.patches.signatureAssetRegex).downloadUrl
val patchesFile = kotlin.io.path.createTempFile().toFile().apply { val patchesFile = kotlin.io.path.createTempFile().toFile().apply {
outputStream().use { URL(patchesDownloadUrl).openStream().copyTo(it) } outputStream().use { URL(patchesDownloadUrl).openStream().copyTo(it) }
} }
val patches = if ( val patches = if (
signatureService.verify( signatureService.verify(
patchesFile, patchesFile,
signatureDownloadUrl, signatureDownloadUrl,
configurationRepository.patches.publicKeyFile, configurationRepository.patches.publicKeyFile,
) )
) { ) {
PatchBundleLoader.Jar(patchesFile) PatchBundleLoader.Jar(patchesFile)
} else { } else {
// Use an empty set of patches if the signature is invalid. // Use an empty set of patches if the signature is invalid.
emptySet() emptySet()
} }
patchesFile.delete() patchesFile.delete()
ByteArrayOutputStream().use { stream -> ByteArrayOutputStream().use { stream ->
PatchUtils.Json.serialize(patches, outputStream = stream) PatchUtils.Json.serialize(patches, outputStream = stream)
stream.toByteArray() stream.toByteArray()
}
} }
} }
} }