diff --git a/src/main/kotlin/app/revanced/api/configuration/repository/AnnouncementRepository.kt b/src/main/kotlin/app/revanced/api/configuration/repository/AnnouncementRepository.kt index eb8475e..9835454 100644 --- a/src/main/kotlin/app/revanced/api/configuration/repository/AnnouncementRepository.kt +++ b/src/main/kotlin/app/revanced/api/configuration/repository/AnnouncementRepository.kt @@ -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.APIResponseAnnouncement import app.revanced.api.configuration.schema.APIResponseAnnouncementId +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking import kotlinx.datetime.* import org.jetbrains.exposed.dao.IntEntity 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.sql.* 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) { init { - transaction { - SchemaUtils.create(AnnouncementTable, AttachmentTable) + runBlocking { + transaction { + SchemaUtils.create(AnnouncementTable, AttachmentTable) + } } } - fun all() = transaction { + suspend fun all() = transaction { buildSet { AnnouncementEntity.all().forEach { announcement -> 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 { AnnouncementEntity.find { AnnouncementTable.channel eq channel }.forEach { announcement -> 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 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. - fun latest() = transaction { + suspend fun latest() = transaction { 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() } - fun latestId() = transaction { + suspend fun latestId() = transaction { AnnouncementEntity.all().maxByOrNull { it.createdAt }?.id?.value?.let { 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 { APIResponseAnnouncementId(it) } } - fun archive( + suspend fun archive( id: Int, archivedAt: LocalDateTime?, ) = 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 { archivedAt = null } } - fun new(new: APIAnnouncement) = transaction { + suspend fun new(new: APIAnnouncement) = transaction { AnnouncementEntity.new announcement@{ author = new.author 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 { author = new.author title = new.title @@ -117,7 +121,8 @@ internal class AnnouncementRepository(private val database: Database) { } } - private fun transaction(block: Transaction.() -> T) = transaction(database, block) + private suspend fun transaction(statement: Transaction.() -> T) = + newSuspendedTransaction(Dispatchers.IO, database, statement = statement) private object AnnouncementTable : IntIdTable() { val author = varchar("author", 32).nullable() diff --git a/src/main/kotlin/app/revanced/api/configuration/services/AnnouncementService.kt b/src/main/kotlin/app/revanced/api/configuration/services/AnnouncementService.kt index 7a0b460..7befd57 100644 --- a/src/main/kotlin/app/revanced/api/configuration/services/AnnouncementService.kt +++ b/src/main/kotlin/app/revanced/api/configuration/services/AnnouncementService.kt @@ -8,28 +8,28 @@ import kotlinx.datetime.LocalDateTime internal class AnnouncementService( private val announcementRepository: AnnouncementRepository, ) { - fun latestId(channel: String): APIResponseAnnouncementId? = announcementRepository.latestId(channel) - fun latestId(): APIResponseAnnouncementId? = announcementRepository.latestId() + suspend fun latestId(channel: String): APIResponseAnnouncementId? = announcementRepository.latestId(channel) + suspend fun latestId(): APIResponseAnnouncementId? = announcementRepository.latestId() - fun latest(channel: String) = announcementRepository.latest(channel) - fun latest() = announcementRepository.latest() + suspend fun latest(channel: String) = announcementRepository.latest(channel) + suspend fun latest() = announcementRepository.latest() - fun all(channel: String) = announcementRepository.all(channel) - fun all() = announcementRepository.all() + suspend fun all(channel: String) = announcementRepository.all(channel) + suspend fun all() = announcementRepository.all() - fun new(new: APIAnnouncement) { + suspend fun new(new: APIAnnouncement) { announcementRepository.new(new) } - fun archive(id: Int, archivedAt: LocalDateTime?) { + suspend fun archive(id: Int, archivedAt: LocalDateTime?) { announcementRepository.archive(id, archivedAt) } - fun unarchive(id: Int) { + suspend fun unarchive(id: Int) { announcementRepository.unarchive(id) } - fun update(id: Int, new: APIAnnouncement) { + suspend fun update(id: Int, new: APIAnnouncement) { announcementRepository.update(id, new) } - fun delete(id: Int) { + suspend fun delete(id: Int) { announcementRepository.delete(id) } } diff --git a/src/main/kotlin/app/revanced/api/configuration/services/PatchesService.kt b/src/main/kotlin/app/revanced/api/configuration/services/PatchesService.kt index abc107d..2024b67 100644 --- a/src/main/kotlin/app/revanced/api/configuration/services/PatchesService.kt +++ b/src/main/kotlin/app/revanced/api/configuration/services/PatchesService.kt @@ -8,6 +8,8 @@ import app.revanced.library.PatchUtils import app.revanced.patcher.PatchBundleLoader import com.github.benmanes.caffeine.cache.Caffeine import io.ktor.util.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.ByteArrayOutputStream import java.net.URL @@ -73,36 +75,38 @@ internal class PatchesService( configurationRepository.patches.repository, ) - return patchesListCache.get(patchesRelease.tag) { - val patchesDownloadUrl = patchesRelease.assets - .first(configurationRepository.patches.assetRegex).downloadUrl + return withContext(Dispatchers.IO) { + patchesListCache.get(patchesRelease.tag) { + val patchesDownloadUrl = patchesRelease.assets + .first(configurationRepository.patches.assetRegex).downloadUrl - val signatureDownloadUrl = patchesRelease.assets - .first(configurationRepository.patches.signatureAssetRegex).downloadUrl + val signatureDownloadUrl = patchesRelease.assets + .first(configurationRepository.patches.signatureAssetRegex).downloadUrl - val patchesFile = kotlin.io.path.createTempFile().toFile().apply { - outputStream().use { URL(patchesDownloadUrl).openStream().copyTo(it) } - } + val patchesFile = kotlin.io.path.createTempFile().toFile().apply { + outputStream().use { URL(patchesDownloadUrl).openStream().copyTo(it) } + } - val patches = if ( - signatureService.verify( - patchesFile, - signatureDownloadUrl, - configurationRepository.patches.publicKeyFile, - ) - ) { - PatchBundleLoader.Jar(patchesFile) - } else { - // Use an empty set of patches if the signature is invalid. - emptySet() - } + val patches = if ( + signatureService.verify( + patchesFile, + signatureDownloadUrl, + configurationRepository.patches.publicKeyFile, + ) + ) { + PatchBundleLoader.Jar(patchesFile) + } else { + // Use an empty set of patches if the signature is invalid. + emptySet() + } - patchesFile.delete() + patchesFile.delete() - ByteArrayOutputStream().use { stream -> - PatchUtils.Json.serialize(patches, outputStream = stream) + ByteArrayOutputStream().use { stream -> + PatchUtils.Json.serialize(patches, outputStream = stream) - stream.toByteArray() + stream.toByteArray() + } } } }