Skip to content

Commit

Permalink
* Fix the expand URLs
Browse files Browse the repository at this point in the history
* Up the max filesize to 25m
* Upgrade Kotlin and add mysql-socket-factory
* Redistribute the Database files and add JDBCDatabase
* Add an option to print the config out
* Add an option for the max workerExecuteTime
  • Loading branch information
UnderMybrella committed Feb 14, 2018
1 parent 05d9b7f commit 5475ca9
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 210 deletions.
3 changes: 2 additions & 1 deletion build.gradle
@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.2.20'
ext.kotlin_version = '1.2.21'
ext.vertx_version = '3.5.0'
ext.jackson_version = '2.9.2'

Expand Down Expand Up @@ -44,6 +44,7 @@ dependencies {
compile "com.h2database:h2:1.4.196"
compile "mysql:mysql-connector-java:5.1.38"
compile "com.zaxxer:HikariCP:2.6.2"
compile "com.google.cloud.sql:mysql-socket-factory:1.0.5"

compile 'org.jsoup:jsoup:1.10.2'
compile 'com.auth0:java-jwt:3.2.0'
Expand Down
13 changes: 9 additions & 4 deletions src/main/kotlin/org/abimon/eternalJukebox/EternalJukebox.kt
Expand Up @@ -21,7 +21,6 @@ import org.abimon.eternalJukebox.data.analysis.SpotifyAnalyser
import org.abimon.eternalJukebox.data.analytics.IAnalyticsProvider
import org.abimon.eternalJukebox.data.analytics.IAnalyticsStorage
import org.abimon.eternalJukebox.data.audio.IAudioSource
import org.abimon.eternalJukebox.data.database.H2Database
import org.abimon.eternalJukebox.data.database.IDatabase
import org.abimon.eternalJukebox.data.storage.IStorage
import org.abimon.eternalJukebox.handlers.OpenGraphHandler
Expand Down Expand Up @@ -108,7 +107,10 @@ object EternalJukebox {
else
config = JukeboxConfig()

log("Loaded config: $config")
if(config.printConfig)
log("Loaded config: $config")
else
log("Loaded config")

// Config Handling

Expand All @@ -117,7 +119,7 @@ object EternalJukebox {

storage = config.storageType.storage

vertx = Vertx.vertx(VertxOptions().setMaxWorkerExecuteTime(90000000000))
vertx = Vertx.vertx(VertxOptions().setMaxWorkerExecuteTime(config.workerExecuteTime))
webserver = vertx.createHttpServer()

val mainRouter = Router.router(vertx)
Expand Down Expand Up @@ -182,7 +184,10 @@ object EternalJukebox {
analyticsProviders = emptyList()
}

database = H2Database
if (isEnabled("database"))
database = config.databaseType.db.objectInstance!!
else
database = EmptyDataAPI

if (isEnabled("audioAPI")) {
apis.add(AudioAPI)
Expand Down
124 changes: 4 additions & 120 deletions src/main/kotlin/org/abimon/eternalJukebox/data/database/H2Database.kt
Expand Up @@ -2,136 +2,20 @@ package org.abimon.eternalJukebox.data.database

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import org.abimon.eternalJukebox.EternalJukebox
import org.abimon.eternalJukebox.objects.ClientInfo
import org.abimon.eternalJukebox.objects.JukeboxAccount
import org.abimon.eternalJukebox.objects.JukeboxInfo
import org.abimon.visi.io.errPrintln
import java.sql.Connection

object H2Database : IDatabase {
val ds: HikariDataSource

override fun provideAudioTrackOverride(id: String, clientInfo: ClientInfo?): String? = use { connection ->
val select = connection.prepareStatement("SELECT * FROM overrides WHERE id=?;")
select.setString(1, id)
select.execute()

val results = select.resultSet
if (results.next())
return@use results.getString("url")
return@use null
}

override fun storeAudioTrackOverride(id: String, newURL: String, clientInfo: ClientInfo?) {
use { connection ->
val insert = connection.prepareStatement("INSERT INTO overrides (id, url) VALUES (?, ?) ON DUPLICATE KEY UPDATE url=VALUES(url);")
insert.setString(1, id)
insert.setString(2, newURL)

insert.execute()
}
}

override fun provideAccountForID(accountID: String, clientInfo: ClientInfo?): JukeboxAccount? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun provideAccountForGoogleID(googleID: String, clientInfo: ClientInfo?): JukeboxAccount? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun storeAccount(clientInfo: ClientInfo?, account: JukeboxAccount) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun providePopularSongs(service: String, count: Int, clientInfo: ClientInfo?): List<JukeboxInfo> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun makeSongPopular(service: String, id: String, clientInfo: ClientInfo?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun provideShortURL(params: Array<String>, clientInfo: ClientInfo?): String = use { connection ->
val joined = buildString {
for (param in params) {
if (length > 4096)
break

if (isNotBlank())
append('&')

append(param)
}
}

val select = connection.prepareStatement("SELECT * FROM short_urls WHERE params=?;")
select.setString(1, joined)
select.execute()

val results = select.resultSet

if (results.first())
return@use results.getString("id")

val id = obtainNewShortID(connection)

val insert = connection.prepareStatement("INSERT INTO short_urls (id, params) VALUES (?, ?);")
insert.setString(1, id)
insert.setString(2, joined)
insert.execute()

return@use id
}

override fun expandShortURL(id: String, clientInfo: ClientInfo?): Array<String>? = use { connection ->
val select = connection.prepareStatement("SELECT * FROM short_urls WHERE id=?;")
select.setString(1, id)
select.execute()

val results = select.resultSet
if(results.first())
return@use results.getString("params").split("&").toTypedArray()

return@use null
}

fun obtainNewShortID(connection: Connection): String {
val preparedSelect = connection.prepareStatement("SELECT * FROM short_urls WHERE id=?")
val range = (0 until 4)
(0 until 4096).forEach {
val id = buildString { for (i in range) append(EternalJukebox.BASE_64_URL[EternalJukebox.secureRandom.nextInt(64)]) }
preparedSelect.setString(1, id)
preparedSelect.execute()
preparedSelect.resultSet.use {
if (!it.isBeforeFirst)
return@obtainNewShortID id
}

println("Generated $id, no success")
}

errPrintln("We've run out of new short IDs to send. This is bad.")

throw IllegalStateException("Run out of IDs")
}
object H2Database: HikariDatabase() {
override val ds: HikariDataSource

init {
val config = HikariConfig()
config.jdbcUrl = "jdbc:h2:./eternal_jukebox"
config.jdbcUrl = "jdbc:h2:./$databaseName"

config.addDataSourceProperty("cachePrepStmts", "true")
config.addDataSourceProperty("prepStmtCacheSize", "250")
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")

ds = HikariDataSource(config)

use { connection ->
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS overrides (id VARCHAR(64) PRIMARY KEY NOT NULL, url VARCHAR(8192) NOT NULL);")
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS short_urls (id VARCHAR(16) PRIMARY KEY NOT NULL, params VARCHAR(4096) NOT NULL);")
}
initialise()
}

infix fun <T> use(op: (Connection) -> T): T = ds.connection.use(op)
}
@@ -0,0 +1,129 @@
package org.abimon.eternalJukebox.data.database

import com.zaxxer.hikari.HikariDataSource
import org.abimon.eternalJukebox.EternalJukebox
import org.abimon.eternalJukebox.objects.ClientInfo
import org.abimon.eternalJukebox.objects.JukeboxAccount
import org.abimon.eternalJukebox.objects.JukeboxInfo
import org.abimon.visi.io.errPrintln
import java.sql.Connection

abstract class HikariDatabase : IDatabase {
abstract val ds: HikariDataSource

override fun provideAudioTrackOverride(id: String, clientInfo: ClientInfo?): String? = use { connection ->
val select = connection.prepareStatement("SELECT * FROM overrides WHERE id=?;")
select.setString(1, id)
select.execute()

val results = select.resultSet
if (results.next())
return@use results.getString("url")
return@use null
}

override fun storeAudioTrackOverride(id: String, newURL: String, clientInfo: ClientInfo?) {
use { connection ->
val insert = connection.prepareStatement("INSERT INTO overrides (id, url) VALUES (?, ?) ON DUPLICATE KEY UPDATE url=VALUES(url);")
insert.setString(1, id)
insert.setString(2, newURL)

insert.execute()
}
}

override fun provideAccountForID(accountID: String, clientInfo: ClientInfo?): JukeboxAccount? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun provideAccountForGoogleID(googleID: String, clientInfo: ClientInfo?): JukeboxAccount? {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun storeAccount(clientInfo: ClientInfo?, account: JukeboxAccount) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun providePopularSongs(service: String, count: Int, clientInfo: ClientInfo?): List<JukeboxInfo> {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun makeSongPopular(service: String, id: String, clientInfo: ClientInfo?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

override fun provideShortURL(params: Array<String>, clientInfo: ClientInfo?): String = use { connection ->
val joined = buildString {
for (param in params) {
if (length > 4096)
break

if (isNotBlank())
append('&')

append(param)
}
}

val select = connection.prepareStatement("SELECT * FROM short_urls WHERE params=?;")
select.setString(1, joined)
select.execute()

val results = select.resultSet

if (results.first())
return@use results.getString("id")

val id = obtainNewShortID(connection)

val insert = connection.prepareStatement("INSERT INTO short_urls (id, params) VALUES (?, ?);")
insert.setString(1, id)
insert.setString(2, joined)
insert.execute()

return@use id
}

override fun expandShortURL(id: String, clientInfo: ClientInfo?): Array<String>? = use { connection ->
val select = connection.prepareStatement("SELECT * FROM short_urls WHERE id=?;")
select.setString(1, id)
select.execute()

val results = select.resultSet
if (results.first())
return@use results.getString("params").split("&").toTypedArray()

return@use null
}

fun obtainNewShortID(connection: Connection): String {
val preparedSelect = connection.prepareStatement("SELECT * FROM short_urls WHERE id=?")
val range = (0 until 4)
(0 until 4096).forEach {
val id = buildString { for (i in range) append(EternalJukebox.BASE_64_URL[EternalJukebox.secureRandom.nextInt(64)]) }
preparedSelect.setString(1, id)
preparedSelect.execute()
preparedSelect.resultSet.use {
if (!it.isBeforeFirst)
return@obtainNewShortID id
}

println("Generated $id, no success")
}

errPrintln("We've run out of new short IDs to send. This is bad.")

throw IllegalStateException("Run out of IDs")
}

infix fun <T> use(op: (Connection) -> T): T = ds.connection.use(op)

fun initialise() {
use { connection ->
// connection.createStatement().execute("USE $databaseName")

connection.createStatement().execute("CREATE TABLE IF NOT EXISTS overrides (id VARCHAR(64) PRIMARY KEY NOT NULL, url VARCHAR(8192) NOT NULL);")
connection.createStatement().execute("CREATE TABLE IF NOT EXISTS short_urls (id VARCHAR(16) PRIMARY KEY NOT NULL, params VARCHAR(4096) NOT NULL);")
}
}
}
@@ -1,10 +1,16 @@
package org.abimon.eternalJukebox.data.database

import org.abimon.eternalJukebox.EternalJukebox
import org.abimon.eternalJukebox.objects.ClientInfo
import org.abimon.eternalJukebox.objects.JukeboxAccount
import org.abimon.eternalJukebox.objects.JukeboxInfo

interface IDatabase {
val databaseOptions
get() = EternalJukebox.config.databaseOptions
val databaseName
get() = databaseOptions["databaseName"] ?: "eternal_jukebox"

fun provideAudioTrackOverride(id: String, clientInfo: ClientInfo?): String?
fun storeAudioTrackOverride(id: String, newURL: String, clientInfo: ClientInfo?)
fun provideAccountForID(accountID: String, clientInfo: ClientInfo?): JukeboxAccount?
Expand Down
@@ -0,0 +1,31 @@
package org.abimon.eternalJukebox.data.database

import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource

object JDBCDatabase: HikariDatabase() {
override val ds: HikariDataSource

init {
val config = HikariConfig()
config.jdbcUrl = databaseOptions["jdbcUrl"]?.toString() ?: throw IllegalStateException("jdbcUrl was not provided!")

config.username = databaseOptions["username"]?.toString()
config.password = databaseOptions["password"]?.toString()

val cloudSqlInstance = databaseOptions["cloudSqlInstance"]?.toString()

if(cloudSqlInstance != null) {
config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.SocketFactory")
config.addDataSourceProperty("cloudSqlInstance", cloudSqlInstance)
}

config.addDataSourceProperty("cachePrepStmts", databaseOptions["cachePrepStmts"]?.toString() ?: "true")
config.addDataSourceProperty("prepStmtCacheSize", databaseOptions["prepStmtCacheSize"]?.toString() ?: "250")
config.addDataSourceProperty("prepStmtCacheSqlLimit", databaseOptions["prepStmtCacheSqlLimit"]?.toString() ?: "2048")

ds = HikariDataSource(config)

initialise()
}
}
@@ -1,11 +1,15 @@
package org.abimon.eternalJukebox.data.storage

import io.vertx.ext.web.RoutingContext
import org.abimon.eternalJukebox.EternalJukebox
import org.abimon.eternalJukebox.objects.ClientInfo
import org.abimon.eternalJukebox.objects.EnumStorageType
import org.abimon.visi.io.DataSource

interface IStorage {
val storageOptions
get() = EternalJukebox.config.storageOptions

/**
* Should we store this type of storage?
*/
Expand Down

0 comments on commit 5475ca9

Please sign in to comment.