summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt')
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt145
1 files changed, 94 insertions, 51 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
index 01afd94..8ea6653 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
@@ -4,10 +4,13 @@ package io.dico.parcels2.storage.exposed
import com.zaxxer.hikari.HikariDataSource
import io.dico.parcels2.*
+import io.dico.parcels2.storage.AddedDataPair
import io.dico.parcels2.storage.Backing
import io.dico.parcels2.storage.DataPair
+import io.dico.parcels2.util.synchronized
import io.dico.parcels2.util.toUUID
import kotlinx.coroutines.experimental.*
+import kotlinx.coroutines.experimental.channels.ArrayChannel
import kotlinx.coroutines.experimental.channels.LinkedListChannel
import kotlinx.coroutines.experimental.channels.ReceiveChannel
import kotlinx.coroutines.experimental.channels.SendChannel
@@ -21,10 +24,9 @@ import javax.sql.DataSource
class ExposedDatabaseException(message: String? = null) : Exception(message)
-class ExposedBacking(private val dataSourceFactory: () -> DataSource,
- private val poolSize: Int) : Backing {
+class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSize: Int) : Backing {
override val name get() = "Exposed"
- val dispatcher: CoroutineDispatcher = newFixedThreadPoolContext(4, "Parcels StorageThread")
+ override val dispatcher: ThreadPoolDispatcher = newFixedThreadPoolContext(poolSize, "Parcels StorageThread")
private var dataSource: DataSource? = null
private var database: Database? = null
@@ -40,6 +42,24 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
return channel
}
+ override fun <T> openChannelForWriting(action: Backing.(T) -> Unit): SendChannel<T> {
+ val channel = ArrayChannel<T>(poolSize * 2)
+
+ repeat(poolSize) {
+ launch(dispatcher) {
+ try {
+ while (true) {
+ action(channel.receive())
+ }
+ } catch (ex: Exception) {
+ // channel closed
+ }
+ }
+ }
+
+ return channel
+ }
+
private fun <T> transaction(statement: Transaction.() -> T) = transaction(database!!, statement)
companion object {
@@ -51,25 +71,54 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
}
override fun init() {
- if (isShutdown || isConnected) throw IllegalStateException()
-
- dataSource = dataSourceFactory()
- database = Database.connect(dataSource!!)
- transaction(database!!) {
- create(WorldsT, OwnersT, ParcelsT, ParcelOptionsT, AddedLocalT, AddedGlobalT)
+ synchronized {
+ if (isShutdown || isConnected) throw IllegalStateException()
+ dataSource = dataSourceFactory()
+ database = Database.connect(dataSource!!)
+ transaction(database!!) {
+ create(WorldsT, ProfilesT, ParcelsT, ParcelOptionsT, AddedLocalT, AddedGlobalT)
+ }
}
}
override fun shutdown() {
- if (isShutdown) throw IllegalStateException()
- dataSource?.let {
- (it as? HikariDataSource)?.close()
+ synchronized {
+ if (isShutdown) throw IllegalStateException()
+ dataSource?.let {
+ (it as? HikariDataSource)?.close()
+ }
+ database = null
+ isShutdown = true
}
- database = null
- isShutdown = true
}
- override fun produceParcelData(channel: SendChannel<DataPair>, parcels: Sequence<ParcelId>) {
+ private fun PlayerProfile.toOwnerProfile(): PlayerProfile {
+ if (this is PlayerProfile.Star) return PlayerProfile.Fake(PlayerProfile.Star.name)
+ return this
+ }
+
+ private fun PlayerProfile.Unresolved.toResolvedProfile(): PlayerProfile.Real {
+ return resolve(getPlayerUuidForName(name) ?: throwException())
+ }
+
+ private fun PlayerProfile.toResolvedProfile(): PlayerProfile {
+ if (this is PlayerProfile.Unresolved) return toResolvedProfile()
+ return this
+ }
+
+ private fun PlayerProfile.toRealProfile(): PlayerProfile.Real = when (this) {
+ is PlayerProfile.Real -> this
+ is PlayerProfile.Fake -> throw IllegalArgumentException("Fake profiles are not accepted")
+ is PlayerProfile.Unresolved -> toResolvedProfile()
+ else -> throw InternalError("Case should not be reached")
+ }
+
+ override fun getPlayerUuidForName(name: String): UUID? {
+ return ProfilesT.slice(ProfilesT.uuid).select { ProfilesT.name.upperCase() eq name.toUpperCase() }
+ .firstOrNull()?.let { it[ProfilesT.uuid]?.toUUID() }
+ }
+
+ override fun transmitParcelData(channel: SendChannel<DataPair>, parcels: Sequence<ParcelId>) {
for (parcel in parcels) {
val data = readParcelData(parcel)
channel.offer(parcel to data)
@@ -77,25 +126,25 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
channel.close()
}
- override fun produceAllParcelData(channel: SendChannel<Pair<ParcelId, ParcelData?>>) = ctransaction<Unit> {
+ override fun transmitAllParcelData(channel: SendChannel<DataPair>) {
ParcelsT.selectAll().forEach { row ->
- val parcel = ParcelsT.getId(row) ?: return@forEach
+ val parcel = ParcelsT.getItem(row) ?: return@forEach
val data = rowToParcelData(row)
- channel.send(parcel to data)
+ channel.offer(parcel to data)
}
channel.close()
}
- override fun readParcelData(parcel: ParcelId): ParcelData? = transaction {
- val row = ParcelsT.getRow(parcel) ?: return@transaction null
- rowToParcelData(row)
+ override fun readParcelData(parcel: ParcelId): ParcelData? {
+ val row = ParcelsT.getRow(parcel) ?: return null
+ return rowToParcelData(row)
}
- override fun getOwnedParcels(user: ParcelOwner): List<ParcelId> = transaction {
- val user_id = OwnersT.getId(user) ?: return@transaction emptyList()
- ParcelsT.select { ParcelsT.owner_id eq user_id }
+ override fun getOwnedParcels(user: PlayerProfile): List<ParcelId> {
+ val user_id = ProfilesT.getId(user.toOwnerProfile()) ?: return emptyList()
+ return ParcelsT.select { ParcelsT.owner_id eq user_id }
.orderBy(ParcelsT.claim_time, isAsc = true)
- .mapNotNull(ParcelsT::getId)
+ .mapNotNull(ParcelsT::getItem)
.toList()
}
@@ -123,21 +172,21 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
setParcelOwner(parcel, data.owner)
- for ((uuid, status) in data.addedMap) {
- setLocalPlayerStatus(parcel, uuid, status)
+ for ((profile, status) in data.addedMap) {
+ AddedLocalT.setPlayerStatus(parcel, profile, status)
}
setParcelAllowsInteractInputs(parcel, data.allowInteractInputs)
setParcelAllowsInteractInventory(parcel, data.allowInteractInventory)
}
- override fun setParcelOwner(parcel: ParcelId, owner: ParcelOwner?) = transaction {
+ override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) {
val id = if (owner == null)
- ParcelsT.getId(parcel) ?: return@transaction
+ ParcelsT.getId(parcel) ?: return
else
ParcelsT.getOrInitId(parcel)
- val owner_id = owner?.let { OwnersT.getOrInitId(it) }
+ val owner_id = owner?.let { ProfilesT.getOrInitId(it.toOwnerProfile()) }
val time = owner?.let { DateTime.now() }
ParcelsT.update({ ParcelsT.id eq id }) {
@@ -146,11 +195,11 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
}
}
- override fun setLocalPlayerStatus(parcel: ParcelId, player: UUID, status: AddedStatus) = transaction {
- AddedLocalT.setPlayerStatus(parcel, player, status)
+ override fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus) {
+ AddedLocalT.setPlayerStatus(parcel, player.toRealProfile(), status)
}
- override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean): Unit = transaction {
+ override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean) {
val id = ParcelsT.getOrInitId(parcel)
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
it[ParcelOptionsT.parcel_id] = id
@@ -158,7 +207,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
}
}
- override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean): Unit = transaction {
+ override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) {
val id = ParcelsT.getOrInitId(parcel)
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
it[ParcelOptionsT.parcel_id] = id
@@ -166,36 +215,30 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource,
}
}
- override fun produceAllGlobalAddedData(channel: SendChannel<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>) = ctransaction<Unit> {
+ override fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>) {
AddedGlobalT.sendAllAddedData(channel)
channel.close()
}
- override fun readGlobalAddedData(owner: ParcelOwner): MutableMap<UUID, AddedStatus> = transaction {
- return@transaction AddedGlobalT.readAddedData(OwnersT.getId(owner) ?: return@transaction hashMapOf())
+ override fun readGlobalAddedData(owner: PlayerProfile): MutableAddedDataMap {
+ return AddedGlobalT.readAddedData(ProfilesT.getId(owner.toOwnerProfile()) ?: return hashMapOf())
}
- override fun setGlobalPlayerStatus(owner: ParcelOwner, player: UUID, status: AddedStatus) = transaction {
- AddedGlobalT.setPlayerStatus(owner, player, status)
+ override fun setGlobalPlayerStatus(owner: PlayerProfile, player: PlayerProfile, status: AddedStatus) {
+ AddedGlobalT.setPlayerStatus(owner, player.toRealProfile(), status)
}
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
- owner = row[ParcelsT.owner_id]?.let { OwnersT.getId(it) }
+ owner = row[ParcelsT.owner_id]?.let { ProfilesT.getItem(it) }
since = row[ParcelsT.claim_time]
- val parcelId = row[ParcelsT.id]
- addedMap = AddedLocalT.readAddedData(parcelId)
-
- AddedLocalT.select { AddedLocalT.attach_id eq parcelId }.forEach {
- val uuid = it[AddedLocalT.player_uuid].toUUID()
- val status = if (it[AddedLocalT.allowed_flag]) AddedStatus.ALLOWED else AddedStatus.BANNED
- setAddedStatus(uuid, status)
+ val id = row[ParcelsT.id]
+ ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
+ allowInteractInputs = optrow[ParcelOptionsT.interact_inputs]
+ allowInteractInventory = optrow[ParcelOptionsT.interact_inventory]
}
- ParcelOptionsT.select { ParcelOptionsT.parcel_id eq parcelId }.firstOrNull()?.let {
- allowInteractInputs = it[ParcelOptionsT.interact_inputs]
- allowInteractInventory = it[ParcelOptionsT.interact_inventory]
- }
+ addedMap = AddedLocalT.readAddedData(id)
}
}