Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MySQL Support #47

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ shadowJar {
relocate("net.kyori", "me.clip.voteparty.libs.kyori")
relocate("com.cryptomorin.xseries", "me.clip.voteparty.libs.xseries")
relocate("kotlin", "me.clip.voteparty.libs.kotlin")
relocate("co.aikar.idb", "me.clip.voteparty.libs.idb")
relocate("com.zaxxer", "me.clip.voteparty.libs.hikari")
archiveFileName = "VoteParty-${project.version}.jar"
}

Expand All @@ -82,6 +84,10 @@ dependencies {
implementation 'net.kyori:adventure-api:4.11.0'
implementation 'net.kyori:adventure-text-minimessage:4.11.0'

// MySQL?
implementation "co.aikar:idb-core:1.0.0-SNAPSHOT"
implementation "com.zaxxer:HikariCP:4.0.3"

implementation project(":version")
implementation project(":version_old")
implementation project(":version_new")
Expand Down
12 changes: 7 additions & 5 deletions src/main/kotlin/me/clip/voteparty/conf/VotePartyConfiguration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@ import me.clip.voteparty.conf.sections.EffectsSettings
import me.clip.voteparty.conf.sections.HookSettings
import me.clip.voteparty.conf.sections.PartySettings
import me.clip.voteparty.conf.sections.PluginSettings
import me.clip.voteparty.conf.sections.StorageSettings
import me.clip.voteparty.conf.sections.VoteSettings
import java.io.File

internal class VotePartyConfiguration(file: File) : SettingsManagerImpl(YamlFileResource(file.toPath()), ConfigurationDataBuilder.createConfiguration(SECTIONS), VoteMigrationService())
{

private companion object
{

private val SECTIONS = listOf(
PluginSettings::class.java,
StorageSettings::class.java,
HookSettings::class.java,
CrateSettings::class.java,
EffectsSettings::class.java,
PartySettings::class.java,
VoteSettings::class.java
)

}
}

}
6 changes: 6 additions & 0 deletions src/main/kotlin/me/clip/voteparty/conf/objects/SQLData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package me.clip.voteparty.conf.objects

internal data class SQLData(var user: String = "username",
var password: String = "password",
var database: String = "database",
var host: String = "host")
18 changes: 18 additions & 0 deletions src/main/kotlin/me/clip/voteparty/conf/sections/StorageSettings.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package me.clip.voteparty.conf.sections

import ch.jalu.configme.Comment
import ch.jalu.configme.SettingsHolder
import ch.jalu.configme.properties.Property
import ch.jalu.configme.properties.PropertyInitializer.newBeanProperty
import ch.jalu.configme.properties.PropertyInitializer.newProperty
import me.clip.voteparty.conf.objects.SQLData

internal object StorageSettings : SettingsHolder {

@JvmField
@Comment("What storage backend would you like to use? We currently support JSON & MySQL")
val BACKEND: Property<String> = newProperty("storage.backend", "JSON")

@JvmField
val SQL : Property<SQLData> = newBeanProperty(SQLData::class.java, "storage.mysql_settings", SQLData("user", "pass", "database", "localhost"))
}
22 changes: 12 additions & 10 deletions src/main/kotlin/me/clip/voteparty/data/base/DatabaseVotePlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,27 @@ import java.util.UUID

internal interface DatabaseVotePlayer : Addon, State
{

override fun load()

override fun kill()


fun load(uuid: UUID): User?

fun save(data: User)


fun load(uuid: Collection<UUID>): Map<UUID, User?>
{
return uuid.associateWith(::load)
}

fun save(data: Collection<User>)
{
data.forEach(::save)
}

}

fun reset(data: User)

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,24 @@ import java.util.logging.Level

internal class DatabaseVotePlayerGson(override val plugin: VotePartyPlugin) : DatabaseVotePlayer
{

private lateinit var gson: Gson


override fun load()
{
val builder = GsonBuilder().disableHtmlEscaping().enableComplexMapKeySerialization().setPrettyPrinting().serializeNulls()
gson = builder.create()

plugin.dataFolder.resolve("players").mkdirs()
}

override fun kill()
{

}


override fun load(uuid: UUID): User?
{
return try
Expand All @@ -40,7 +40,7 @@ internal class DatabaseVotePlayerGson(override val plugin: VotePartyPlugin) : Da
null
}
}

override fun save(data: User)
{
try
Expand All @@ -52,16 +52,21 @@ internal class DatabaseVotePlayerGson(override val plugin: VotePartyPlugin) : Da
logger.log(Level.SEVERE, "failed to save player:${data.uuid}", ex)
}
}


override fun reset(data: User)
{
data.reset()
}

override fun load(uuid: Collection<UUID>): Map<UUID, User?>
{
if (uuid.isNotEmpty())
{
return super.load(uuid)
}

val files = plugin.dataFolder.resolve("players").listFiles() ?: return emptyMap()

return files.mapNotNull()
{
try
Expand All @@ -74,5 +79,5 @@ internal class DatabaseVotePlayerGson(override val plugin: VotePartyPlugin) : Da
}
}.associateWith(::load)
}
}

}
116 changes: 116 additions & 0 deletions src/main/kotlin/me/clip/voteparty/data/impl/DatabaseVotePlayerMySQL.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package me.clip.voteparty.data.impl

import co.aikar.idb.DB
import co.aikar.idb.Database
import co.aikar.idb.DatabaseOptions
import co.aikar.idb.PooledDatabaseOptions
import me.clip.voteparty.conf.sections.StorageSettings
import me.clip.voteparty.data.base.DatabaseVotePlayer
import me.clip.voteparty.plugin.VotePartyPlugin
import me.clip.voteparty.user.User
import java.math.BigInteger
import java.sql.SQLException
import java.util.UUID
import java.util.logging.Level

internal class DatabaseVotePlayerMySQL(override val plugin: VotePartyPlugin) : DatabaseVotePlayer
{

private lateinit var database: Database

override fun load()
{
val sql = party.conf().getProperty(StorageSettings.SQL)

val options = DatabaseOptions.builder()
.mysql(sql.user, sql.password, sql.database, sql.host)
.logger(plugin.logger)
.poolName("VoteParty Database")
.build()

database = PooledDatabaseOptions.builder().options(options).createHikariDatabase()

DB.setGlobalDatabase(database)

try
{
database.executeUpdate(
"CREATE TABLE IF NOT EXISTS `voteparty_players` (" +
" `uuid` varchar(255) NOT NULL," +
" `name` varchar(100) NOT NULL," +
" `claimable` int(9) unsigned NOT NULL," +
" PRIMARY KEY (`uuid`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8;"
)

database.executeUpdate(
"CREATE TABLE IF NOT EXISTS `voteparty_votes` (" +
" `timestamp` bigint(20) unsigned NOT NULL," +
" `uuid` varchar(255) NOT NULL," +
" PRIMARY KEY (`timestamp`)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8;"
)

}
catch (ex: SQLException)
{
throw RuntimeException("Error while creating database table:", ex)
}
}

override fun kill()
{
DB.close()
}

override fun load(uuid: UUID): User?
{
return try
{
val row = database.getFirstRow("SELECT name, claimable FROM voteparty_players WHERE uuid = ?", uuid.toString())
val user = User(uuid, row.getString("name"), mutableListOf(), row.getInt("claimable"))

database.getResults("SELECT timestamp FROM voteparty_votes WHERE uuid = ?", uuid.toString()).forEach { vote ->
val stamp : BigInteger = vote.get("timestamp")
user.voted(stamp.toLong())
}
user
}
catch (ex: SQLException)
{
logger.log(Level.SEVERE, "failed to load player:$uuid", ex)
null
}
}

override fun save(data: User)
{
database.executeInsert("INSERT INTO voteparty_players (uuid, name, claimable) VALUES(?, ?, ?) ON DUPLICATE " +
"KEY UPDATE name = ?, claimable = ?", data.uuid.toString(), data.name, data.claimable, data.name, data.claimable)

data.votes().forEach { vote ->
database.executeInsert("INSERT IGNORE INTO voteparty_votes (timestamp, uuid) VALUES(?, ?)", vote, data.uuid.toString())
}
}

override fun reset(data: User)
{
database.executeUpdate("DELETE FROM voteparty_votes WHERE UUID = ?", data.uuid.toString())
}

override fun load(uuid: Collection<UUID>): Map<UUID, User?>
{
if (uuid.isNotEmpty())
{
return super.load(uuid)
}

val data = mutableListOf<UUID>()

database.getResults("SELECT uuid from voteparty_players").forEach { results ->
data.add(UUID.fromString(results.getString("uuid")))
}

return data.associateWith(::load)
}
}
15 changes: 10 additions & 5 deletions src/main/kotlin/me/clip/voteparty/user/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,32 @@ import java.util.UUID

data class User(val uuid: UUID, var name: String, private val data: MutableList<Long>, var claimable: Int)
{

fun voted()
{
data += System.currentTimeMillis()
}


fun voted(time: Long)
{
data += time
}

fun votes(): List<Long>
{
return data
}

fun hasVotedBefore(): Boolean
{
return data.isNotEmpty()
}

fun reset()
{
data.clear()
}

fun player() : OfflinePlayer
{
return Bukkit.getOfflinePlayer(uuid)
Expand Down
13 changes: 11 additions & 2 deletions src/main/kotlin/me/clip/voteparty/user/UsersHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package me.clip.voteparty.user

import me.clip.voteparty.base.Addon
import me.clip.voteparty.base.State
import me.clip.voteparty.conf.sections.StorageSettings
import me.clip.voteparty.data.base.DatabaseVotePlayer
import me.clip.voteparty.data.impl.DatabaseVotePlayerGson
import me.clip.voteparty.data.impl.DatabaseVotePlayerMySQL
import me.clip.voteparty.leaderboard.LeaderboardUser
import me.clip.voteparty.plugin.VotePartyPlugin
import org.bukkit.OfflinePlayer
Expand All @@ -24,12 +27,18 @@ import java.util.concurrent.TimeUnit
class UsersHandler(override val plugin: VotePartyPlugin) : Addon, State, Listener
{

private val database = DatabaseVotePlayerGson(plugin)
private lateinit var database : DatabaseVotePlayer
private val cached = mutableMapOf<Any, User>()


override fun load()
{
database = if (party.conf().getProperty(StorageSettings.BACKEND).equals("mysql", true)) {
DatabaseVotePlayerMySQL(plugin)
} else {
DatabaseVotePlayerGson(plugin)
}

database.load()

database.load(emptyList()).forEach()
Expand Down Expand Up @@ -74,7 +83,7 @@ class UsersHandler(override val plugin: VotePartyPlugin) : Addon, State, Listene

fun reset(player: OfflinePlayer)
{
get(player).reset()
database.reset(get(player))
}

fun saveAll()
Expand Down