mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Implement entity listeners for Game and Library
This commit is contained in:
@@ -15,7 +15,7 @@ class GameEndpoint(
|
||||
private val gameService: GameService
|
||||
) {
|
||||
fun subscribe(): Flux<GameEvent> {
|
||||
return gameService.subscribe()
|
||||
return GameService.subscribe()
|
||||
}
|
||||
|
||||
fun getAll(): List<GameDto> = gameService.getAll()
|
||||
@@ -25,5 +25,4 @@ class GameEndpoint(
|
||||
|
||||
@RolesAllowed(Role.Names.ADMIN)
|
||||
fun deleteGame(gameId: Long) = gameService.delete(gameId)
|
||||
|
||||
}
|
||||
@@ -17,7 +17,6 @@ import de.grimsi.gameyfin.libraries.Library
|
||||
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadata
|
||||
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataProvider
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import jakarta.persistence.EntityManager
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -37,26 +36,31 @@ class GameService(
|
||||
private val pluginService: PluginService,
|
||||
private val config: ConfigService,
|
||||
private val companyService: CompanyService,
|
||||
private val gameRepository: GameRepository,
|
||||
private val entityManager: EntityManager
|
||||
private val gameRepository: GameRepository
|
||||
) {
|
||||
companion object {
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
/* Websockets */
|
||||
private val gameEvents = Sinks.many().multicast().onBackpressureBuffer<GameEvent>(1024, false)
|
||||
|
||||
fun subscribe(): Flux<GameEvent> {
|
||||
log.debug { "New subscription for gameUpdates" }
|
||||
return gameEvents.asFlux()
|
||||
.doOnSubscribe { log.debug { "Subscriber added to gameEvents [${gameEvents.currentSubscriberCount()}]" } }
|
||||
.doFinally {
|
||||
log.debug { "Subscriber removed from gameEvents with signal type $it [${gameEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
}
|
||||
|
||||
fun emit(event: GameEvent) {
|
||||
gameEvents.tryEmitNext(event)
|
||||
}
|
||||
}
|
||||
|
||||
private val metadataPlugins: List<GameMetadataProvider>
|
||||
get() = pluginManager.getExtensions(GameMetadataProvider::class.java)
|
||||
|
||||
private val gameEvents = Sinks.many().multicast().onBackpressureBuffer<GameEvent>(1024, false)
|
||||
|
||||
fun subscribe(): Flux<GameEvent> {
|
||||
log.debug { "New subscription for gameUpdates" }
|
||||
return gameEvents.asFlux()
|
||||
.doOnSubscribe { log.debug { "Subscriber added to gameEvents [${gameEvents.currentSubscriberCount()}]" } }
|
||||
.doFinally {
|
||||
log.debug { "Subscriber removed from gameEvents with signal type $it [${gameEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
}
|
||||
|
||||
fun getAll(): List<GameDto> {
|
||||
val entities = gameRepository.findAll()
|
||||
@@ -73,16 +77,7 @@ class GameService(
|
||||
game
|
||||
}
|
||||
|
||||
val games = gameRepository.saveAll(gamesToBePersisted)
|
||||
|
||||
// force flush to populate creation and update timestamp
|
||||
entityManager.flush()
|
||||
|
||||
games.forEach { game ->
|
||||
val gameDto = game.toDto()
|
||||
gameEvents.tryEmitNext(GameEvent.Created(gameDto))
|
||||
}
|
||||
return games
|
||||
return gameRepository.saveAll(gamesToBePersisted)
|
||||
}
|
||||
|
||||
fun update(gameUpdateDto: GameUpdateDto) {
|
||||
@@ -94,18 +89,11 @@ class GameService(
|
||||
gameUpdateDto.comment?.let { existingGame.comment = it }
|
||||
gameUpdateDto.summary?.let { existingGame.summary = it }
|
||||
|
||||
val updatedGame = gameRepository.save(existingGame)
|
||||
val updatedGameDto = updatedGame.toDto()
|
||||
gameEvents.tryEmitNext(GameEvent.Updated(updatedGameDto))
|
||||
gameRepository.save(existingGame)
|
||||
}
|
||||
|
||||
fun delete(gameId: Long) {
|
||||
gameRepository.deleteById(gameId)
|
||||
gameEvents.tryEmitNext(GameEvent.Deleted(gameId))
|
||||
}
|
||||
|
||||
fun emitDeletionEvent(gameId: Long) {
|
||||
gameEvents.tryEmitNext(GameEvent.Deleted(gameId))
|
||||
}
|
||||
|
||||
fun matchFromFile(path: Path, library: Library): Game? {
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.net.URI
|
||||
import java.time.Instant
|
||||
|
||||
@Entity
|
||||
@EntityListeners(GameEntityListener::class)
|
||||
class Game(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
import de.grimsi.gameyfin.games.GameService
|
||||
import de.grimsi.gameyfin.games.dto.GameEvent
|
||||
import de.grimsi.gameyfin.games.toDto
|
||||
import jakarta.persistence.PostPersist
|
||||
import jakarta.persistence.PostRemove
|
||||
import jakarta.persistence.PostUpdate
|
||||
|
||||
class GameEntityListener {
|
||||
@PostPersist
|
||||
fun created(game: Game) {
|
||||
val event = GameEvent.Created(game.toDto())
|
||||
GameService.emit(event)
|
||||
}
|
||||
|
||||
@PostUpdate
|
||||
fun updated(game: Game) {
|
||||
val event = GameEvent.Updated(game.toDto())
|
||||
GameService.emit(event)
|
||||
}
|
||||
|
||||
@PostRemove
|
||||
fun deleted(game: Game) {
|
||||
val event = GameEvent.Deleted(game.id!!)
|
||||
GameService.emit(event)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
import de.grimsi.gameyfin.libraries.Library
|
||||
import de.grimsi.gameyfin.libraries.LibraryService
|
||||
import de.grimsi.gameyfin.libraries.dto.LibraryEvent
|
||||
import de.grimsi.gameyfin.libraries.toDto
|
||||
import jakarta.persistence.PostPersist
|
||||
import jakarta.persistence.PostRemove
|
||||
import jakarta.persistence.PostUpdate
|
||||
|
||||
class LibraryEntityListener {
|
||||
@PostPersist
|
||||
fun created(library: Library) {
|
||||
val event = LibraryEvent.Created(library.toDto())
|
||||
LibraryService.emit(event)
|
||||
}
|
||||
|
||||
@PostUpdate
|
||||
fun updated(library: Library) {
|
||||
val event = LibraryEvent.Updated(library.toDto())
|
||||
LibraryService.emit(event)
|
||||
}
|
||||
|
||||
@PostRemove
|
||||
fun deleted(library: Library) {
|
||||
val event = LibraryEvent.Deleted(library.id!!)
|
||||
LibraryService.emit(event)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package de.grimsi.gameyfin.libraries
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import de.grimsi.gameyfin.games.entities.LibraryEntityListener
|
||||
import jakarta.persistence.*
|
||||
|
||||
@Entity
|
||||
@EntityListeners(LibraryEntityListener::class)
|
||||
class Library(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
|
||||
@@ -16,7 +16,7 @@ class LibraryEndpoint(
|
||||
private val libraryService: LibraryService
|
||||
) {
|
||||
fun subscribe(): Flux<LibraryEvent> {
|
||||
return libraryService.subscribe()
|
||||
return LibraryService.subscribe()
|
||||
}
|
||||
|
||||
fun getAll() = libraryService.getAll()
|
||||
|
||||
@@ -28,25 +28,31 @@ class LibraryService(
|
||||
companion object {
|
||||
private val log = KotlinLogging.logger {}
|
||||
private val executor = Executors.newVirtualThreadPerTaskExecutor()
|
||||
|
||||
/* Websockets */
|
||||
private val libraryEvents = Sinks.many().multicast().onBackpressureBuffer<LibraryEvent>(1024, false)
|
||||
|
||||
fun subscribe(): Flux<LibraryEvent> {
|
||||
log.debug { "New subscription for libraryEvents" }
|
||||
return libraryEvents.asFlux()
|
||||
.doOnSubscribe { log.debug { "Subscriber added to libraryEvents [${libraryEvents.currentSubscriberCount()}]" } }
|
||||
.doFinally {
|
||||
log.debug { "Subscriber removed from libraryEvents with signal type $it [${libraryEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
}
|
||||
|
||||
fun emit(event: LibraryEvent) {
|
||||
libraryEvents.tryEmitNext(event)
|
||||
}
|
||||
}
|
||||
|
||||
private val libraryEvents = Sinks.many().multicast().onBackpressureBuffer<LibraryEvent>(1024, false)
|
||||
|
||||
fun subscribe(): Flux<LibraryEvent> {
|
||||
log.debug { "New subscription for libraryEvents" }
|
||||
return libraryEvents.asFlux()
|
||||
.doOnSubscribe { log.debug { "Subscriber added to libraryEvents [${libraryEvents.currentSubscriberCount()}]" } }
|
||||
.doFinally {
|
||||
log.debug { "Subscriber removed from libraryEvents with signal type $it [${libraryEvents.currentSubscriberCount()}]" }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all libraries from the repository.
|
||||
*/
|
||||
fun getAll(): List<LibraryDto> {
|
||||
val entities = libraryRepository.findAll()
|
||||
return entities.map { toDto(it) }
|
||||
return entities.map { it.toDto() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +63,6 @@ class LibraryService(
|
||||
*/
|
||||
fun create(library: LibraryDto) {
|
||||
val entity = libraryRepository.save(toEntity(library))
|
||||
val libraryDto = toDto(entity)
|
||||
libraryEvents.tryEmitNext(LibraryEvent.Created(libraryDto))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,9 +85,7 @@ class LibraryService(
|
||||
)
|
||||
}
|
||||
|
||||
val updatedLibrary = libraryRepository.save(existingLibrary)
|
||||
val updatedLibraryDto = toDto(updatedLibrary)
|
||||
libraryEvents.tryEmitNext(LibraryEvent.Updated(updatedLibraryDto))
|
||||
libraryRepository.save(existingLibrary)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,13 +94,7 @@ class LibraryService(
|
||||
* @param libraryId: ID of the library to delete.
|
||||
*/
|
||||
fun delete(libraryId: Long) {
|
||||
val gameIds = libraryRepository.findByIdOrNull(libraryId)?.games?.mapNotNull { it.id }
|
||||
?: throw IllegalArgumentException("Library with ID $libraryId not found")
|
||||
|
||||
libraryRepository.deleteById(libraryId)
|
||||
|
||||
libraryEvents.tryEmitNext(LibraryEvent.Deleted(libraryId))
|
||||
gameIds.forEach { gameService.emitDeletionEvent(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,29 +252,6 @@ class LibraryService(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Library entity to a LibraryDto.
|
||||
*
|
||||
* @param library: The Library entity to convert.
|
||||
* @return The converted LibraryDto.
|
||||
*/
|
||||
private fun toDto(library: Library): LibraryDto {
|
||||
val libraryId = library.id ?: throw IllegalArgumentException("Library ID is null")
|
||||
|
||||
val statsDto = LibraryStatsDto(
|
||||
gamesCount = library.games.size,
|
||||
downloadedGamesCount = library.games.sumOf { it.downloadCount }
|
||||
)
|
||||
|
||||
return LibraryDto(
|
||||
id = libraryId,
|
||||
name = library.name,
|
||||
directories = library.directories.map { DirectoryMappingDto(it.internalPath, it.externalPath) },
|
||||
games = library.games.mapNotNull { it.id },
|
||||
stats = statsDto
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection of games to the library.
|
||||
*
|
||||
@@ -306,4 +279,21 @@ class LibraryService(
|
||||
}.toMutableList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun Library.toDto(): LibraryDto {
|
||||
val libraryId = this.id ?: throw IllegalArgumentException("Library ID is null")
|
||||
|
||||
val statsDto = LibraryStatsDto(
|
||||
gamesCount = this.games.size,
|
||||
downloadedGamesCount = this.games.sumOf { it.downloadCount }
|
||||
)
|
||||
|
||||
return LibraryDto(
|
||||
id = libraryId,
|
||||
name = this.name,
|
||||
directories = this.directories.map { DirectoryMappingDto(it.internalPath, it.externalPath) },
|
||||
games = this.games.mapNotNull { it.id },
|
||||
stats = statsDto
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user