From 1eed613b2a0c186e2ac4af3f3a6c1ddca23958fa Mon Sep 17 00:00:00 2001 From: rnentjes Date: Fri, 9 Aug 2024 19:55:15 +0200 Subject: [PATCH] Move stuff into base --- build.gradle.kts | 2 +- .../nl/astraeus/vst/string/PhysicalString.kt | 32 ++-- .../nl/astraeus/vst/string/logger/Logger.kt | 53 ------ .../kotlin/nl/astraeus/vst/string/Main.kt | 8 +- .../vst/string/audio/AudioContextHandler.kt | 2 +- .../nl/astraeus/vst/string/view/MainView.kt | 55 ------ .../vst/string/view/PhysicalStringView.kt | 6 +- .../astraeus/vst/string/view/WaveformView.kt | 3 +- .../nl/astraeus/vst/string/GenerateId.kt | 16 -- .../kotlin/nl/astraeus/vst/string/Main.kt | 42 +---- .../kotlin/nl/astraeus/vst/string/Settings.kt | 50 ------ .../nl/astraeus/vst/string/db/BaseDao.kt | 170 ------------------ .../nl/astraeus/vst/string/db/Database.kt | 99 ---------- .../nl/astraeus/vst/string/db/Entity.kt | 16 -- .../nl/astraeus/vst/string/db/Migrations.kt | 106 ----------- .../nl/astraeus/vst/string/db/PatchDao.kt | 31 ---- .../nl/astraeus/vst/string/db/PatchEntity.kt | 12 -- .../vst/string/db/PatchEntityQueryProvider.kt | 64 ------- .../nl/astraeus/vst/string/web/Index.kt | 42 ----- .../astraeus/vst/string/web/RequestHandler.kt | 128 ------------- .../nl/astraeus/vst/string/web/Session.kt | 5 - 21 files changed, 40 insertions(+), 902 deletions(-) delete mode 100644 src/commonMain/kotlin/nl/astraeus/vst/string/logger/Logger.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/GenerateId.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/Settings.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/BaseDao.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/Database.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/Entity.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/Migrations.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchDao.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntity.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntityQueryProvider.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/web/Index.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/web/RequestHandler.kt delete mode 100644 src/jvmMain/kotlin/nl/astraeus/vst/string/web/Session.kt diff --git a/build.gradle.kts b/build.gradle.kts index e172502..81a47f5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -39,13 +39,13 @@ kotlin { //base api("nl.astraeus:kotlin-css-generator:1.0.7") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") + implementation("nl.astraeus:vst-ui-base:1.1.0-SNAPSHOT") } } val jsMain by getting { dependencies { //base implementation("nl.astraeus:kotlin-komponent-js:1.2.2") - implementation("nl.astraeus:vst-ui-base:1.0.0-SNAPSHOT") } } val jsTest by getting { diff --git a/common/src/commonMain/kotlin/nl/astraeus/vst/string/PhysicalString.kt b/common/src/commonMain/kotlin/nl/astraeus/vst/string/PhysicalString.kt index 1ba91f7..2ca4f94 100644 --- a/common/src/commonMain/kotlin/nl/astraeus/vst/string/PhysicalString.kt +++ b/common/src/commonMain/kotlin/nl/astraeus/vst/string/PhysicalString.kt @@ -7,6 +7,8 @@ import kotlin.math.round expect fun randomDouble(): Double +const val BUFFER_MULTIPLY = 4 + @ExperimentalJsExport @JsExport class PhysicalString( @@ -14,9 +16,9 @@ class PhysicalString( var damping: Double, ) { val sampleLength = 1.0 / sampleRate.toDouble() - val maxLength = sampleRate / Note.G9.freq + val maxLength = sampleRate / Note.NO01.freq var length = 1 - val buffer = Array(maxLength.toInt() + 1) { 0.0 } + val buffer = Array((maxLength * BUFFER_MULTIPLY).toInt() + 1) { 0.0 } var sample = 0 var index = 0 var remaining = 0.0 @@ -26,7 +28,7 @@ class PhysicalString( fun pluck(note: Note, velocity: Double, smoothing: Int = 0) { available = false currentNote = note - length = round(sampleRate / note.freq).toInt() + length = round(BUFFER_MULTIPLY * sampleRate / note.freq).toInt() sample = 0 index = 0 @@ -37,7 +39,7 @@ class PhysicalString( buffer[i] = -randomDouble() * velocity } //buffer[i] = (randomDouble() - 0.5) * 2.0 * velocity - //buffer[i] = sin(PI * 2 * i/length) + //buffer[i] = sin(PI * 2 * i/length) * randomDouble() * velocity //buffer[i] = (i/length.toDouble() * 2.0) - 1.0 //if (i < length / 2) { 1.0 } else { -1.0 } } repeat(smoothing) { @@ -58,18 +60,20 @@ class PhysicalString( fun tick(): Double { val result = buffer[index] - var newValue = 0.0 - newValue += getValueFromBuffer(index + 1) * 0.2 - newValue += getValueFromBuffer(index + 2) * 0.3 - newValue += getValueFromBuffer(index + 3) * 0.3 - newValue += getValueFromBuffer(index + 4) * 0.2 -// newValue += getValueFromBuffer(index + 5) * 0.2 -// newValue += getValueFromBuffer(index + 6) * 0.3 - newValue *= damping + repeat(BUFFER_MULTIPLY) { + var newValue = 0.0 + newValue += getValueFromBuffer(index + 1) * 0.1 + newValue += getValueFromBuffer(index + 2) * 0.15 + newValue += getValueFromBuffer(index + 3) * 0.25 + newValue += getValueFromBuffer(index + 4) * 0.25 + newValue += getValueFromBuffer(index + 5) * 0.15 + newValue += getValueFromBuffer(index + 6) * 0.1 + newValue *= damping - buffer[index] = newValue + buffer[index] = newValue - index = (index + 1) % length + index = (index + 1) % length + } return result } diff --git a/src/commonMain/kotlin/nl/astraeus/vst/string/logger/Logger.kt b/src/commonMain/kotlin/nl/astraeus/vst/string/logger/Logger.kt deleted file mode 100644 index e60eadd..0000000 --- a/src/commonMain/kotlin/nl/astraeus/vst/string/logger/Logger.kt +++ /dev/null @@ -1,53 +0,0 @@ -package nl.astraeus.vst.string.logger - -val log = Logger - -enum class LogLevel { - TRACE, - DEBUG, - INFO, - WARN, - ERROR, - FATAL -} - -object Logger { - var level: LogLevel = LogLevel.INFO - - fun trace(message: () -> String?) { - if (level.ordinal <= LogLevel.TRACE.ordinal) { - println("TRACE: ${message()}") - } - } - - fun debug(message: () -> String?) { - if (level.ordinal <= LogLevel.DEBUG.ordinal) { - println("DEBUG: ${message()}") - } - } - - fun info(message: () -> String?) { - if (level.ordinal <= LogLevel.INFO.ordinal) { - println("INFO: ${message()}") - } - } - - fun warn(e: Throwable? = null, message: () -> String?) { - if (level.ordinal <= LogLevel.WARN.ordinal) { - println("WARN: ${message()}") - e?.printStackTrace() - } - } - - fun error(e: Throwable? = null, message: () -> String?) { - if (level.ordinal <= LogLevel.ERROR.ordinal) { - println("ERROR: ${message()}") - e?.printStackTrace() - } - } - - fun fatal(e: Throwable, message: () -> String?) { - println("FATAL: ${message()}") - e.printStackTrace() - } -} diff --git a/src/jsMain/kotlin/nl/astraeus/vst/string/Main.kt b/src/jsMain/kotlin/nl/astraeus/vst/string/Main.kt index 7c08d4f..4e2b919 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/string/Main.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/string/Main.kt @@ -3,18 +3,24 @@ package nl.astraeus.vst.string import kotlinx.browser.document import nl.astraeus.komp.Komponent import nl.astraeus.komp.UnsafeMode +import nl.astraeus.vst.string.audio.VstStringWorklet import nl.astraeus.vst.string.logger.log import nl.astraeus.vst.string.midi.Midi import nl.astraeus.vst.string.view.MainView import nl.astraeus.vst.string.ws.WebsocketClient import nl.astraeus.vst.ui.css.CssSettings +import nl.astraeus.vst.ui.view.BaseVstView fun main() { CssSettings.shortId = false CssSettings.preFix = "vst-chip" Komponent.unsafeMode = UnsafeMode.UNSAFE_SVG_ONLY - Komponent.create(document.body!!, MainView) + Komponent.create(document.body!!, BaseVstView("VST Guiter", MainView) { + VstStringWorklet.create { + WebsocketClient.send("LOAD\n") + } + }) Midi.start() diff --git a/src/jsMain/kotlin/nl/astraeus/vst/string/audio/AudioContextHandler.kt b/src/jsMain/kotlin/nl/astraeus/vst/string/audio/AudioContextHandler.kt index fcfa5ee..7bca63c 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/string/audio/AudioContextHandler.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/string/audio/AudioContextHandler.kt @@ -7,4 +7,4 @@ object AudioContextHandler { -} \ No newline at end of file +} diff --git a/src/jsMain/kotlin/nl/astraeus/vst/string/view/MainView.kt b/src/jsMain/kotlin/nl/astraeus/vst/string/view/MainView.kt index 5657840..ac6755f 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/string/view/MainView.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/string/view/MainView.kt @@ -18,15 +18,10 @@ import nl.astraeus.css.properties.Display import nl.astraeus.css.properties.FlexDirection import nl.astraeus.css.properties.FontWeight import nl.astraeus.css.properties.JustifyContent -import nl.astraeus.css.properties.Position -import nl.astraeus.css.properties.Transform import nl.astraeus.css.properties.em -import nl.astraeus.css.properties.hsla import nl.astraeus.css.properties.prc import nl.astraeus.css.properties.px import nl.astraeus.css.properties.rem -import nl.astraeus.css.properties.vh -import nl.astraeus.css.properties.vw import nl.astraeus.css.style.Style import nl.astraeus.css.style.cls import nl.astraeus.komp.HtmlBuilder @@ -48,7 +43,6 @@ import org.w3c.dom.HTMLSelectElement object MainView : Komponent(), CssName { private var messages: MutableList = ArrayList() - var started = false val playString = PhysicalStringView( PhysicalString( sampleRate = 48000, @@ -70,22 +64,6 @@ object MainView : Komponent(), CssName { override fun HtmlBuilder.render() { div(MainDivCss.name) { - if (!started) { - div(StartSplashCss.name) { - div(StartBoxCss.name) { - div(StartButtonCss.name) { - +"START" - onClickFunction = { - VstStringWorklet.create { - started = true - requestUpdate() - WebsocketClient.send("LOAD\n") - } - } - } - } - } - } h1 { +"VST Guitar" } @@ -175,9 +153,6 @@ object MainView : Komponent(), CssName { object ButtonBarCss : CssName object SelectedCss : CssName object NoteBarCss : CssName - object StartSplashCss : CssName - object StartBoxCss : CssName - object StartButtonCss : CssName object ControlsCss : CssName private fun css() { @@ -239,36 +214,6 @@ object MainView : Komponent(), CssName { color(Css.currentStyle.mainFontColor) borderRadius(0.25.em) } - select(cls(StartSplashCss)) { - position(Position.fixed) - left(0.px) - top(0.px) - width(100.vw) - height(100.vh) - zIndex(100) - backgroundColor(hsla(32, 0, 5, 0.65)) - - select(cls(StartBoxCss)) { - position(Position.relative) - left(25.vw) - top(25.vh) - width(50.vw) - height(50.vh) - backgroundColor(hsla(239, 50, 10, 1.0)) - borderColor(Css.currentStyle.mainFontColor) - borderWidth(2.px) - - select(cls(StartButtonCss)) { - position(Position.absolute) - left(50.prc) - top(50.prc) - transform(Transform("translate(-50%, -50%)")) - padding(1.rem) - backgroundColor(Css.currentStyle.buttonBackgroundColor) - cursor("pointer") - } - } - } select(ControlsCss.cls()) { display(Display.flex) flexDirection(FlexDirection.row) diff --git a/src/jsMain/kotlin/nl/astraeus/vst/string/view/PhysicalStringView.kt b/src/jsMain/kotlin/nl/astraeus/vst/string/view/PhysicalStringView.kt index 26480f0..92d4c82 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/string/view/PhysicalStringView.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/string/view/PhysicalStringView.kt @@ -40,9 +40,7 @@ class PhysicalStringView( } private fun onAnimationFrame(time: Double) { - if (MainView.started) { - draw() - } + draw() window.requestAnimationFrame(::onAnimationFrame) } @@ -89,7 +87,7 @@ class PhysicalStringView( private fun draw() { val ctx = context - if (ctx != null) { + if (ctx != null && ctx.canvas.isConnected) { val width = ctx.canvas.width.toDouble() val height = ctx.canvas.height.toDouble() val halfHeight = height / 2.0 diff --git a/src/jsMain/kotlin/nl/astraeus/vst/string/view/WaveformView.kt b/src/jsMain/kotlin/nl/astraeus/vst/string/view/WaveformView.kt index a642340..9540aed 100644 --- a/src/jsMain/kotlin/nl/astraeus/vst/string/view/WaveformView.kt +++ b/src/jsMain/kotlin/nl/astraeus/vst/string/view/WaveformView.kt @@ -18,7 +18,7 @@ object WaveformView : Komponent() { } fun onAnimationFrame(time: Double) { - if (MainView.started) { + if (VstStringWorklet.recording == null) { VstStringWorklet.postMessage("start_recording") } @@ -50,6 +50,7 @@ object WaveformView : Komponent() { ctx.stroke() } } + VstStringWorklet.recording = null } } } diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/GenerateId.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/GenerateId.kt deleted file mode 100644 index 428caa2..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/GenerateId.kt +++ /dev/null @@ -1,16 +0,0 @@ -package nl.astraeus.vst.string - -import java.security.SecureRandom - -val idChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" -val random = SecureRandom() - -fun generateId(): String { - val id = StringBuilder() - - for (i in 0 until 8) { - id.append(idChars[random.nextInt(idChars.length)]) - } - - return id.toString() -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/Main.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/Main.kt index dd2b8f6..e4e1ad9 100644 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/Main.kt +++ b/src/jvmMain/kotlin/nl/astraeus/vst/string/Main.kt @@ -1,15 +1,10 @@ package nl.astraeus.vst.string -import com.zaxxer.hikari.HikariConfig -import io.undertow.Undertow -import io.undertow.UndertowOptions -import io.undertow.server.session.InMemorySessionManager -import io.undertow.server.session.SessionAttachmentHandler -import io.undertow.server.session.SessionCookieConfig -import nl.astraeus.vst.string.db.Database +import nl.astraeus.vst.base.Settings +import nl.astraeus.vst.base.db.Database +import nl.astraeus.vst.base.web.UndertowServer import nl.astraeus.vst.string.logger.LogLevel import nl.astraeus.vst.string.logger.Logger -import nl.astraeus.vst.string.web.RequestHandler fun main() { Logger.level = LogLevel.DEBUG @@ -18,32 +13,13 @@ fun main() { e.printStackTrace() } - Class.forName("nl.astraeus.jdbc.Driver") + Settings.port = 9004 + Settings.jdbcStatsPort = 6004 - Database.initialize(HikariConfig().apply { - driverClassName = "nl.astraeus.jdbc.Driver" - jdbcUrl = "jdbc:stat:webServerPort=6002:jdbc:sqlite:data/chip.db" - username = "sa" - password = "" - maximumPoolSize = 25 - isAutoCommit = false + Database.start() - validate() - }) - - val sessionHandler = SessionAttachmentHandler( - InMemorySessionManager("vst-session-manager"), - SessionCookieConfig() + UndertowServer.start( + "Vst String", + "/vst-string-worklet-ui.js" ) - sessionHandler.setNext(RequestHandler) - - val server = Undertow.builder() - .addHttpListener(Settings.port, "localhost") - .setIoThreads(4) - .setHandler(sessionHandler) - .setServerOption(UndertowOptions.SHUTDOWN_TIMEOUT, 1000) - .build() - - println("Starting server at port ${Settings.port}...") - server?.start() } diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/Settings.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/Settings.kt deleted file mode 100644 index 7680d99..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/Settings.kt +++ /dev/null @@ -1,50 +0,0 @@ -package nl.astraeus.vst.string - -import java.io.File -import java.io.FileInputStream -import java.util.* - -object Settings { - var runningAsRoot: Boolean = false - var port = 9004 - var sslPort = 8443 - var connectionTimeout = 30000 - - var jdbcDriver = "nl.astraeus.jdbc.Driver" - var jdbcConnectionUrl = "jdbc:stat:webServerPort=6001:jdbc:sqlite:data/srp.db" - var jdbcUser = "sa" - var jdbcPassword = "" - - var adminUser = "rnentjes" - var adminPassword = "9/SG_Bd}9gWz~?j\\A.U]n9]OO" - - fun getPropertiesFromFile(filename: String): Properties? { - val propertiesFile = File(filename) - return if (propertiesFile.exists()) { - val properties = Properties() - FileInputStream(propertiesFile).use { - properties.load(it) - } - properties - } else { - null - } - } - - fun readProperties(args: Array) { - val filename = if (args.isNotEmpty()) args[0] else "srp.properties" - val properties = getPropertiesFromFile(filename) ?: return // return if properties couldn't be loaded - - runningAsRoot = properties.getProperty("runningAsRoot", runningAsRoot.toString()).toBoolean() - port = properties.getProperty("port", port.toString()).toInt() - sslPort = properties.getProperty("sslPort", sslPort.toString()).toInt() - connectionTimeout = properties.getProperty("connectionTimeout", connectionTimeout.toString()).toInt() - jdbcDriver = properties.getProperty("jdbcDriver", jdbcDriver) - jdbcConnectionUrl = properties.getProperty("jdbcConnectionUrl", jdbcConnectionUrl) - jdbcUser = properties.getProperty("jdbcUser", jdbcUser) - jdbcPassword = properties.getProperty("jdbcPassword", jdbcPassword) - - adminUser = properties.getProperty("adminUser", adminUser) - adminPassword = properties.getProperty("adminPassword", adminPassword) - } -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/BaseDao.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/BaseDao.kt deleted file mode 100644 index 725fe9a..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/BaseDao.kt +++ /dev/null @@ -1,170 +0,0 @@ -package nl.astraeus.vst.string.db - -import kotlinx.datetime.Instant -import nl.astraeus.vst.string.logger.log -import java.sql.PreparedStatement -import java.sql.ResultSet -import java.sql.Timestamp - -fun Instant.toSqlTimestamp() = Timestamp(this.toEpochMilliseconds()) -fun Timestamp.toDateTimeInstant() = Instant.fromEpochMilliseconds(this.time) - -data class SqlStatement( - val sql: String, - val prepareParameters: T.(PreparedStatement) -> Unit -) - -data class SqlQuery( - val sql: String, - val resultMapper: (ResultSet) -> T -) - -abstract class QueryProvider { - abstract val tableName: String - open val idQuery: String - get() = "SELECT * FROM $tableName WHERE ID = ?" - abstract val resultSetMapper: (ResultSet) -> T - open val find: SqlQuery - get() = SqlQuery( - idQuery, - resultSetMapper - ) - abstract val insert: SqlStatement - abstract val update: SqlStatement - open val delete: SqlStatement - get() = SqlStatement( - "DELETE FROM $tableName WHERE ID = ?" - ) { ps -> - ps.setLong(1, getPK()[0] as Long) - } -} - -abstract class BaseDao { - abstract val queryProvider: QueryProvider - open val autogeneratedPrimaryKey: Boolean = true - - open fun insert(entity: T) { - executeInsert(entity, "insert", queryProvider.insert) - } - - open fun update(entity: T): Int = executeUpdate( - entity, - "update", - queryProvider.update, - true - ) - - open fun upsert(entity: T) { - if ((entity.getPK()[0] as Long) == 0L) { - insert(entity) - } else { - update(entity) - } - } - - open fun delete(entity: T) { - executeUpdate(entity, "delete", queryProvider.delete, true) - } - - open fun find( - id: Long - ): T? { - return executeQuery( - "find", - queryProvider.find - ) { ps -> - ps.setLong(1, id) - }.firstOrNull() - } - - protected fun executeSQLUpdate( - sql: String, - parameterSetter: (PreparedStatement) -> Unit - ): Int { - return transaction { con -> - con.prepareStatement(sql).use { ps -> - parameterSetter(ps) - - ps.executeUpdate() - } - } - } - - protected fun executeQuery( - label: String, - statement: SqlQuery, - prepareParameters: (PreparedStatement) -> Unit, - ): List { - return transaction { con -> - log.debug { "Executing query [$label] - [${statement.sql}]" } - val result = mutableListOf() - - con.prepareStatement(statement.sql)?.use { ps -> - prepareParameters(ps) - - val rs = ps.executeQuery() - - while (rs.next()) { - result.add(statement.resultMapper(rs)) - } - } - - result - } - } - - protected fun executeInsert( - entity: T, - label: String, - statement: SqlStatement, - checkSingleRow: Boolean = false - ) { - transaction { con -> - log.debug { "Executing insert [$label] - [${statement.sql}] - [$entity]" } - con.prepareStatement(statement.sql)?.use { ps -> - statement.prepareParameters(entity, ps) - - val rows = if (checkSingleRow) { - ps.execute() - 1 - } else { - ps.executeUpdate() - } - - if (autogeneratedPrimaryKey) { - val keyResult = ps.generatedKeys - if (keyResult.next()) { - entity.setPK(arrayOf(keyResult.getLong(1))) - } - } - - check(rows == 1) { - "Statement [$label] affected more than 1 row! [${statement.sql}]" - } - } - } - } - - protected fun executeUpdate( - entity: T, - label: String, - statement: SqlStatement, - checkSingleRow: Boolean = false - ): Int = transaction { con -> - var rows = 1 - - log.debug { "Executing update [$label] - [${statement.sql}] - [$entity]" } - con.prepareStatement(statement.sql)?.use { ps -> - statement.prepareParameters(entity, ps) - - rows = ps.executeUpdate() - - check(checkSingleRow || rows == 1) { - "Statement [$label] affected more than 1 row! [${statement.sql}]" - } - } - - rows - } - -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Database.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Database.kt deleted file mode 100644 index 8f62db2..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Database.kt +++ /dev/null @@ -1,99 +0,0 @@ -package nl.astraeus.vst.string.db - -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import java.sql.Connection -import java.util.* -import java.util.concurrent.atomic.AtomicBoolean - -enum class TxScope { - REQUIRED, - /* if needed we need to switch db, sqlite only allows one writer/connection */ - //REQUIRES_NEW -} - -private val currentConnection = ThreadLocal() - -fun transaction( - scope: TxScope = TxScope.REQUIRED, - block: (Connection) -> T -): T { - val hasConnection = currentConnection.get() != null - var oldConnection: Connection? = null - - if (!hasConnection) { - currentConnection.set(Database.getConnection()) - /* - } else if (scope == TxScope.REQUIRES_NEW) { - oldConnection = currentConnection.get() - - currentConnection.set(Database.getConnection()) - */ - } - - val connection = currentConnection.get() - - try { - val result = block(connection) - - connection.commit() - - return result - } finally { - if (!hasConnection) { - currentConnection.set(oldConnection) - connection.close() - } - } -} - -object Database { - - var ds: HikariDataSource? = null - - fun initialize(config: HikariConfig) { - val properties = Properties() - properties["journal_mode"] = "WAL" - - - config.dataSourceProperties = properties - config.addDataSourceProperty("cachePrepStmts", "true") - config.addDataSourceProperty("prepStmtCacheSize", "250") - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048") - - ds = HikariDataSource(config) - Migrations.databaseVersionTableCreated = AtomicBoolean(false) - Migrations.updateDatabaseIfNeeded() - } - - fun getConnection() = ds?.connection ?: error("Database has not been initialized!") - - /* - val ds: HikariDataSource - - init { - val properties = Properties() - properties["journal_mode"] = "WAL" - - val config = HikariConfig().apply { - driverClassName = "nl.astraeus.jdbc.Driver" - jdbcUrl = "jdbc:stat:webServerPort=6001:jdbc:sqlite:data/daw3.db" - username = "sa" - password = "" - maximumPoolSize = 25 - isAutoCommit = false - dataSourceProperties = properties - validate() - } - - config.addDataSourceProperty("cachePrepStmts", "true") - config.addDataSourceProperty("prepStmtCacheSize", "250") - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048") - - ds = HikariDataSource(config) - } - - fun getConnection() = ds.connection - */ - -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Entity.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Entity.kt deleted file mode 100644 index 9e32f19..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Entity.kt +++ /dev/null @@ -1,16 +0,0 @@ -package nl.astraeus.vst.string.db - -interface Entity { - fun getPK(): Array - fun setPK(pks: Array) -} - -interface EntityId : Entity { - var id: Long - - override fun getPK(): Array = arrayOf(id) - - override fun setPK(pks: Array) { - id = pks[0] as Long - } -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Migrations.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Migrations.kt deleted file mode 100644 index 754ad3b..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/Migrations.kt +++ /dev/null @@ -1,106 +0,0 @@ -package nl.astraeus.vst.string.db - -import nl.astraeus.vst.string.logger.log -import java.sql.Connection -import java.sql.SQLException -import java.sql.Timestamp -import java.util.concurrent.atomic.AtomicBoolean - -sealed class Migration { - class Query( - val query: String - ) : Migration() { - override fun toString(): String { - return query - } - } - - class Code( - val code: (Connection) -> Unit - ) : Migration() { - override fun toString(): String { - return code.toString() - } - } -} - -val DATABASE_MIGRATIONS = arrayOf( - Migration.Query( - """ - CREATE TABLE DATABASE_VERSION ( - ID INTEGER PRIMARY KEY, - QUERY TEXT, - EXECUTED TIMESTAMP - ) - """.trimIndent() - ), - Migration.Query(PATCH_CREATE_QUERY), -) - -object Migrations { - var databaseVersionTableCreated = AtomicBoolean(false) - - fun updateDatabaseIfNeeded() { - try { - transaction { con -> - con.prepareStatement( - """ - SELECT MAX(ID) FROM DATABASE_VERSION - """.trimIndent() - ).use { ps -> - ps.executeQuery().use { rs -> - databaseVersionTableCreated.compareAndSet(false, true) - - if (rs.next()) { - val maxId = rs.getInt(1) - - for (index in maxId + 1.. - log.debug { - "Executing migration $index - [${DATABASE_MIGRATIONS[index]}]" - } - val description = when ( - val migration = DATABASE_MIGRATIONS[index] - ) { - is Migration.Query -> { - con.prepareStatement(migration.query).use { ps -> - ps.execute() - } - - migration.query - } - - is Migration.Code -> { - migration.code(con) - - migration.code.toString() - } - } - con.prepareStatement("INSERT INTO DATABASE_VERSION VALUES (?, ?, ?)").use { ps -> - ps.setInt(1, index) - ps.setString(2, description) - ps.setTimestamp(3, Timestamp(System.currentTimeMillis())) - - ps.execute() - } - } - } - -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchDao.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchDao.kt deleted file mode 100644 index c74b208..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchDao.kt +++ /dev/null @@ -1,31 +0,0 @@ -package nl.astraeus.vst.string.db - -object PatchDao : BaseDao() { - - override val queryProvider: QueryProvider - get() = PatchEntityQueryProvider - - fun create( - patchId: String, - patch: String - ): PatchEntity { - val result = PatchEntity( - 0, - patchId, - patch - ) - - return result - } - - fun findById(patchId: String): PatchEntity? = executeQuery( - "findById", - SqlQuery( - "SELECT * FROM ${queryProvider.tableName} WHERE PATCH_ID = ?", - queryProvider.resultSetMapper - ) - ) { ps -> - ps.setString(1, patchId) - }.firstOrNull() - -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntity.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntity.kt deleted file mode 100644 index 1276e7d..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntity.kt +++ /dev/null @@ -1,12 +0,0 @@ -package nl.astraeus.vst.string.db - -import kotlinx.datetime.Clock -import kotlinx.datetime.Instant - -data class PatchEntity( - override var id: Long, - var patchId: String, - var patch: String, - var created: Instant = Clock.System.now(), - var updated: Instant = Clock.System.now(), -) : EntityId \ No newline at end of file diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntityQueryProvider.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntityQueryProvider.kt deleted file mode 100644 index 3bea56e..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/db/PatchEntityQueryProvider.kt +++ /dev/null @@ -1,64 +0,0 @@ -package nl.astraeus.vst.string.db - -import java.sql.ResultSet -import java.sql.Types - -val PATCH_CREATE_QUERY = """ - CREATE TABLE INSTRUMENTS ( - ID INTEGER PRIMARY KEY AUTOINCREMENT, - PATCH_ID TEXT, - PATCH TEXT, - CREATED TIMESTAMP, - UPDATED TIMESTAMP - ) - """.trimIndent() - -object PatchEntityQueryProvider : QueryProvider() { - override val tableName: String - get() = "INSTRUMENTS" - override val resultSetMapper: (ResultSet) -> PatchEntity - get() = { rs -> - PatchEntity( - rs.getLong(1), - rs.getString(2), - rs.getString(3), - rs.getTimestamp(4).toDateTimeInstant(), - rs.getTimestamp(5).toDateTimeInstant() - ) - } - override val insert: SqlStatement - get() = SqlStatement( - """ - INSERT INTO $tableName ( - ID, - PATCH_ID, - PATCH, - CREATED, - UPDATED - ) VALUES ( - ?,?,?,?,? - ) - """.trimIndent() - ) { ps -> - ps.setNull(1, Types.BIGINT) - ps.setString(2, patchId) - ps.setString(3, patch) - ps.setTimestamp(4, created.toSqlTimestamp()) - ps.setTimestamp(5, updated.toSqlTimestamp()) - } - override val update: SqlStatement - get() = SqlStatement( - """ - UPDATE $tableName - SET PATCH_ID = ?, - PATCH = ?, - UPDATED = ? - WHERE ID = ? - """.trimIndent() - ) { ps -> - ps.setString(1, patchId) - ps.setString(2, patch) - ps.setTimestamp(3, updated.toSqlTimestamp()) - ps.setLong(4, id) - } -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Index.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Index.kt deleted file mode 100644 index d7c91b9..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Index.kt +++ /dev/null @@ -1,42 +0,0 @@ -package nl.astraeus.vst.string.web - -import kotlinx.html.body -import kotlinx.html.head -import kotlinx.html.html -import kotlinx.html.meta -import kotlinx.html.script -import kotlinx.html.stream.appendHTML -import kotlinx.html.title - -fun generateIndex(patch: String?): String { - val result = StringBuilder(); - - if (patch == null) { - result.appendHTML(true).html { - head { - title { +"VST String" } - } - body { - script { - type = "application/javascript" - src = "/vst-string-worklet-ui.js" - } - } - } - } else { - result.appendHTML(true).html { - head { - title { +"VST Chip" } - meta { - httpEquiv = "refresh" - content = "0; url=/patch/$patch" - } - } - body { - +"Redirecting to patch $patch..." - } - } - } - - return result.toString() -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/RequestHandler.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/web/RequestHandler.kt deleted file mode 100644 index 4b6aaca..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/RequestHandler.kt +++ /dev/null @@ -1,128 +0,0 @@ -package nl.astraeus.vst.string.web - -import io.undertow.Handlers.websocket -import io.undertow.server.HttpHandler -import io.undertow.server.HttpServerExchange -import io.undertow.server.handlers.PathHandler -import io.undertow.server.handlers.resource.PathResourceManager -import io.undertow.server.handlers.resource.ResourceHandler -import io.undertow.server.session.Session -import io.undertow.server.session.SessionConfig -import io.undertow.server.session.SessionManager -import io.undertow.websockets.WebSocketConnectionCallback -import io.undertow.websockets.core.AbstractReceiveListener -import io.undertow.websockets.core.BufferedBinaryMessage -import io.undertow.websockets.core.BufferedTextMessage -import io.undertow.websockets.core.WebSocketChannel -import io.undertow.websockets.core.WebSockets -import io.undertow.websockets.spi.WebSocketHttpExchange -import nl.astraeus.vst.string.db.PatchDao -import nl.astraeus.vst.string.db.PatchEntity -import nl.astraeus.vst.string.db.transaction -import nl.astraeus.vst.string.generateId -import java.nio.file.Paths - -class WebsocketHandler( - val session: Session? -) : AbstractReceiveListener(), WebSocketConnectionCallback { - - override fun onConnect(exchange: WebSocketHttpExchange, channel: WebSocketChannel) { - channel.receiveSetter.set(this) - channel.resumeReceives() - } - - override fun onFullTextMessage(channel: WebSocketChannel, message: BufferedTextMessage) { - val vstSession = session?.getAttribute("html-session") as? VstSession - - val data = message.data - val commandLength = data.indexOf('\n') - if (commandLength > 0) { - val command = data.substring(0, commandLength) - val value = data.substring(commandLength + 1) - - when (command) { - "SAVE" -> { - val patchId = vstSession?.patchId - if (patchId != null) { - transaction { - val patchEntity = PatchDao.findById(patchId) - - if (patchEntity != null) { - PatchDao.update(patchEntity.copy(patch = value)) - } else { - PatchDao.insert(PatchEntity(0, patchId, value)) - } - } - WebSockets.sendText("SAVED\n$patchId", channel, null) - } - } - - "LOAD" -> { - val patchId = vstSession?.patchId - if (patchId != null) { - transaction { - val patchEntity = PatchDao.findById(patchId) - - if (patchEntity != null) { - WebSockets.sendText("LOAD\n${patchEntity.patch}", channel, null) - } - } - } - } - } - } - } - - override fun onFullBinaryMessage(channel: WebSocketChannel?, message: BufferedBinaryMessage?) { - // do nothing - } -} - -object WebsocketConnectHandler : HttpHandler { - override fun handleRequest(exchange: HttpServerExchange) { - val sessionManager = exchange.getAttachment(SessionManager.ATTACHMENT_KEY) - val sessionConfig = exchange.getAttachment(SessionConfig.ATTACHMENT_KEY) - - val httpSession: Session? = sessionManager.getSession(exchange, sessionConfig) - - websocket(WebsocketHandler(httpSession)).handleRequest(exchange) - } -} - -object PatchHandler : HttpHandler { - override fun handleRequest(exchange: HttpServerExchange) { - if (exchange.requestPath.startsWith("/patch/")) { - val patchId = exchange.requestPath.substring(7) - val sessionManager = exchange.getAttachment(SessionManager.ATTACHMENT_KEY) - val sessionConfig = exchange.getAttachment(SessionConfig.ATTACHMENT_KEY) - var httpSession: Session? = sessionManager.getSession(exchange, sessionConfig) - - if (httpSession == null) { - httpSession = sessionManager.createSession(exchange, sessionConfig) - } - httpSession?.setAttribute("html-session", VstSession(patchId)) - - exchange.responseSender.send(generateIndex(null)) - } else { - val patchId = generateId() - - exchange.responseSender.send(generateIndex(patchId)) - } - } -} - -object RequestHandler : HttpHandler { - val resourceHandler = ResourceHandler(PathResourceManager(Paths.get("web"))) - val pathHandler = PathHandler(resourceHandler) - - init { - pathHandler.addExactPath("/", PatchHandler) - pathHandler.addExactPath("/index.html", PatchHandler) - pathHandler.addPrefixPath("/patch", PatchHandler) - pathHandler.addExactPath("/ws", WebsocketConnectHandler) - } - - override fun handleRequest(exchange: HttpServerExchange) { - pathHandler.handleRequest(exchange) - } -} diff --git a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Session.kt b/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Session.kt deleted file mode 100644 index 068e1c9..0000000 --- a/src/jvmMain/kotlin/nl/astraeus/vst/string/web/Session.kt +++ /dev/null @@ -1,5 +0,0 @@ -package nl.astraeus.vst.string.web - -class VstSession( - val patchId: String -) \ No newline at end of file