Skip to content

feat/spark#6

Draft
ammodev wants to merge 5 commits intoversion/1.21.11from
feat/spark
Draft

feat/spark#6
ammodev wants to merge 5 commits intoversion/1.21.11from
feat/spark

Conversation

@ammodev
Copy link
Copy Markdown
Contributor

@ammodev ammodev commented Mar 28, 2026

No description provided.

Copilot AI review requested due to automatic review settings March 28, 2026 03:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors SurfStats into a client + microservice architecture using RabbitMQ packets for persistence, moving DB writes out of the Paper plugin and into a standalone microservice.

Changes:

  • Split surf-stats-core into surf-stats-core-common (packets) and surf-stats-core-client (file parsing, diff tracking, Rabbit client).
  • Add surf-stats-microservice to receive RabbitMQ requests and persist servers/players/stats via Exposed R2DBC tables.
  • Update Paper plugin wiring and dependencies to use the new client services and required RabbitMQ module.

Reviewed changes

Copilot reviewed 51 out of 64 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
surf-stats-paper/src/main/kotlin/dev/slne/surf/stats/paper/listener/PlayerStatsListener.kt Switches listener integration to the new client API and updated quit signature.
surf-stats-paper/src/main/kotlin/dev/slne/surf/stats/paper/SurfStatsPlugin.kt Updates lifecycle to use statsInstance + periodic diff saving with UUID-only processing.
surf-stats-paper/src/main/kotlin/dev/slne/surf/stats/paper/PaperStatsInstance.kt Rebinds Paper service implementation to new core-client StatsInstance.
surf-stats-paper/build.gradle.kts Updates dependencies to surf-stats-core-client and adds required rabbit/core wiring.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/handler/StatsPacketHandler.kt Adds Rabbit handler to save current/diff stats batches and respond with failed UUIDs.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/handler/ServerPacketHandler.kt Adds Rabbit handler to ensure server row exists.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/handler/PlayerPacketHandler.kt Adds Rabbit handler to ensure player row exists.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/StatKeysTable.kt Introduces microservice-local stat key dimension table (Key transform).
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/StatCategoriesTable.kt Introduces microservice-local stat category dimension table (Key transform).
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/ServersTable.kt Moves/renames servers table into microservice package.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/PlayersTable.kt Moves/renames players table into microservice package.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/PlayerStatsTable.kt Updates current stats table columns to use Key transforms for FK references.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/tables/PlayerStatsHistoryTable.kt Updates history table to use Key transforms and indexes for diff storage.
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/db/StatsDatabaseService.kt Implements persistence operations (ensure server/player, save current/diff batches).
surf-stats-microservice/src/main/kotlin/dev/slne/surf/stats/microservice/StatsMicroservice.kt Adds the standalone microservice bootstrap wiring for DB + RabbitMQ.
surf-stats-microservice/build.gradle.kts Adds standalone + microservice gradle config and core-common dependency.
surf-stats-core/surf-stats-core-common/src/main/kotlin/dev/slne/surf/stats/core/common/packets/StatsUuidResponsePacket.kt Adds response packet for returning failed UUIDs.
surf-stats-core/surf-stats-core-common/src/main/kotlin/dev/slne/surf/stats/core/common/packets/SaveStatsRequestPacket.kt Adds request packet for saving current/diff batches.
surf-stats-core/surf-stats-core-common/src/main/kotlin/dev/slne/surf/stats/core/common/packets/SaveServerRequestPacket.kt Adds request packet to ensure server metadata exists.
surf-stats-core/surf-stats-core-common/src/main/kotlin/dev/slne/surf/stats/core/common/packets/SavePlayerRequestPacket.kt Adds request packet to ensure player metadata exists.
surf-stats-core/surf-stats-core-common/build.gradle.kts Enables microservice rabbit common module support.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/service/StatisticsManagerService.kt Introduces client-side snapshot/diff service API.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/service/StatisticsManagerServiceImpl.kt Implements snapshot caching + diff computation with Caffeine.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/repository/PlayerStatsRepository.kt Updates repository contract (UUID-only) for new model types.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/repository/PlayerStatsRepositoryImpl.kt Reworks file-backed loading and error fallback to empty stats.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/json/StatsJsonModel.kt Updates JSON model to produce typed keys for stats entries.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/json/StatsFileService.kt Updates file service contract (removes name-based overloads).
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/json/StatsFileServiceImpl.kt Reworks file parsing to new PlayerStats model and typed keys.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/SurfStatsApiImpl.kt New client API implementation: compute diffs and send RabbitMQ save requests.
surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/StatsInstance.kt New client instance providing RabbitMQ connectivity + server registration.
surf-stats-core/surf-stats-core-client/build.gradle.kts Adds client module build config with rabbit client API.
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/model/StatEntry.kt Changes stat keys/categories to serializable Key types and adds serialization.
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/model/PlayerStats.kt Replaces prior player-identifying fields with playerUuid/serverName + Collection impl.
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/model/PlayerStatsBatch.kt Redefines batch payload to be serialization/Rabbit-friendly.
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/SurfStatsApi.kt Simplifies SurfStats API surface to UUID-based processing and save/get operations.
surf-stats-api/build.gradle.kts Switches stats API module to the core gradle plugin.
surf-stats-core/src/test/resources/stats/9e94922b-c7b0-43f4-9fab-7c5ff9b07061.json Removes old test resource JSON (tests removed as part of refactor).
surf-stats-core/src/test/resources/stats/47c09dc5-1e14-409f-80c0-c031df3acb13.json Removes old test resource JSON (tests removed as part of refactor).
surf-stats-core/src/test/kotlin/dev/slne/surf/stats/core/service/StatsFileServiceImplTest.kt Removes old file service tests.
surf-stats-core/src/test/kotlin/dev/slne/surf/stats/core/service/StatisticsManagerServiceImplTest.kt Removes old diff/snapshot tests.
surf-stats-core/src/test/kotlin/dev/slne/surf/stats/core/repository/PlayerStatsRepositoryImplTest.kt Removes old repository tests.
surf-stats-core/src/test/kotlin/dev/slne/surf/stats/core/json/StatsJsonModelTest.kt Removes old JSON model tests.
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/service/StatisticsManagerServiceImpl.kt Removes old in-core implementation in favor of new client module.
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/database/StatsDatabaseService.kt Removes old in-core DB persistence in favor of microservice.
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/api/SurfStatsApiImpl.kt Removes old in-core SurfStatsApi implementation in favor of client module.
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/AbstractStatsInstance.kt Removes old instance abstraction (DB-init responsibilities moved).
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/database/table/StatKeysTable.kt Removes old core DB table definition (moved to microservice).
surf-stats-core/src/main/kotlin/dev/slne/surf/stats/core/database/table/StatCategoriesTable.kt Removes old core DB table definition (moved to microservice).
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/service/StatisticsManagerService.kt Removes old API-level statistics manager service (replaced by client module).
surf-stats-api/src/main/kotlin/dev/slne/surf/stats/api/StatsInstance.kt Removes old API-level instance interface (replaced by client StatsInstance).
settings.gradle.kts Updates module includes for core split + adds microservice module.
gradle/libs.versions.toml Removes old surf-database version catalog entry (moved to plugin wiring).
gradle.properties Bumps project version to 2.0.1-SNAPSHOT.
build.gradle.kts Adds microservice gradle plugin to buildscript classpath.
Comments suppressed due to low confidence (1)

surf-stats-core/surf-stats-core-client/src/main/kotlin/dev/slne/surf/stats/core/client/json/StatsJsonModel.kt:41

  • In statsMap construction, the inner destructured variable is named key, which shadows the imported key(...) function. As written, key(key) will try to invoke the local String variable and won’t compile. Rename the destructured variable (e.g., statKey) or qualify the function call so the correct key(...) function is used.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +29 to +42
private suspend fun ensureDimensions(
stats: PlayerStats,
) = suspendTransaction {
val categories = stats.map { it.category }.toSet()
val keys = stats.map { it.key }.toSet()

StatCategoriesTable.batchInsert(categories, ignore = true) { category ->
this[StatCategoriesTable.name] = category
}

StatKeysTable.batchInsert(keys, ignore = true) { key ->
this[StatKeysTable.name] = key
}
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensureDimensions wraps its work in suspendTransaction, but it’s called from inside other suspendTransaction blocks (saveBatch / saveDiffBatch). This creates nested transactions, which can break Exposed R2DBC transaction handling. Make ensureDimensions run within the caller’s transaction (no suspendTransaction inside), or have callers invoke it outside and reuse a single transaction.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +26
suspend fun ensurePlayer(playerUuid: UUID, playerName: String) = suspendTransaction {
PlayersTable.upsert {
it[uuid] = playerUuid
it[name] = playerName
it[dataVersion] = 0
it[updatedAt] = CurrentTimestamp
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensurePlayer always writes dataVersion = 0, and the dataVersion carried on PlayerStatsBatch is never persisted. If the DB schema still expects the client’s DataVersion, this will silently lose that information. Consider either persisting the actual data version from the request (and/or JSON parsing) or removing the column/field if it’s no longer needed.

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +186
// Only update snapshots for players whose diffs were persisted successfully
for (uuid in uuids) {
if (uuid !in failedUuids && diffBatches.any { it.playerUuid == uuid }) {
StatisticsManagerService.updateSnapshot(uuid)
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating snapshots does an any { ... } scan over diffBatches for every uuid in uuids, which is O(n²) on shutdown/periodic saves. Precompute a Set of UUIDs that actually had diffs (e.g., diffBatches.map { it.playerUuid }.toSet()) and check membership instead.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +62
override fun isTracking(uuid: UUID): Boolean {
return snapshotMap.any { it.playerUuid == uuid }
}
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isTracking currently builds a new snapshotMap list and linearly scans it (any { ... }). This is unnecessarily expensive and allocates on every call. Prefer checking the underlying Caffeine cache directly (e.g., getIfPresent(uuid) != null or asMap().containsKey(uuid)).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants