3 Commits
9 changed files with 131 additions and 59 deletions
+2
View File
@@ -48,3 +48,5 @@ bin/
.env
.idea/
artifacts/
clients/compose/src/wasmJsMain/resources/config.json
+62
View File
@@ -0,0 +1,62 @@
# PhoeBench
*Introduction to be done*
## Setup
### Server
The server ZIP files in the releases contain all dependencies, so just unzip it where you want to run the server.
First, set up the environment variables (this cannot currently be done using `.env` files, I think):
- `JWT_AUDIENCE`: the audience to use for the JSON Web Tokens authentication, typically set to your URL;
- `JWT_ISSUER`: the issuer for the authentication tokens, typically also set to your URL;
- `JWT_REALM`: the realm for which the authentication tokens are valid, doesn't matter as there is only one "realm" (I use `phoebench`);
- `JWT_SECRET`: a strong secret key to encrypt the authentication tokens (e.g. generated by `gpg --gen-random --armor 1 128`);
- `PORT`: the port to host the server on;
- `PHOEBENCH_SAFE_CLIENT`: (optional) if you plan on hosting a web client, set this to its URL (for CORS requests);
- `PHOEBENCH_DEV_CLIENT_PORT`: (development only) port to enable CORS requests from `localhost` and `127.0.0.1`.
Next, set up the database variables (recommended through a `.env` file):
- `DATABASE_URL`: JDBC URL to connect to the database;
- `DATABASE_DRIVER`: fully-qualified name of the JDBC driver to connect to the database with;
- `DATABASE_USER`: (if needed) username for the database;
- `DATABASE_PASSWORD`: (if needed) password for the database.
The server currently supports SQLite and MariaDB as databases, using the following settings:
```
# SQLite
DATABASE_URL=jdbc:sqlite:/path/to/db/file.db
DATABASE_DRIVER=org.sqlite.JDBC
# SQLite does not need user/password
# MariaDB
DATABASE_URL=jdbc:mariadb://host:port/database-name
DATABASE_DRIVER=org.mariadb.jdbc.Driver
DATABASE_USER=username
DATABASE_PASSWORD=pass
```
For SQLite, don't forget to substitute `/path/to/db/file.db` (with the path to where the database should be stored).
For MariaDB, don't forget to substitute `host`, `port`, `database-name`, `username`, and `pass` (`host:port` will typically be `localhost:3306`).
To use MariaDB, you will need to create the database and user through its administration interface.
### JVM Client
The JVM client does not require any additional setup.
Simply unzip the client ZIP for your platform (currently only built for Linux), and run `bin/com.jaytux.phoebench.clients` from the unzip location.
However, to avoid having to log in again every time you start the app, it is recommended to ensure you have a working keyring set up.
### WASM Client
The WASM/JS client ZIP contains files that can be statically served, including all dependencies.
As the WASM files can take some time to load over the network, it is recommended to modify the `index.html` file to contain some sort of loading screen.
As for setup - you need to create a file called `config.json` with the following content:
```json
{
"server": "server url"
}
```
Replace `server url` with the URL of the server to connect to (don't forget to add it as `PHOEBENCH_SAFE_CLIENT` to the server, see above).
For deployment, this file should be in the same directory where the ZIP was extracted.
For development, it should be under `/clients/compose/src/wasmJsMain/resources/` to ensure correct loading.
### CLI Client
The CLI client does not require any additional setup, simply use Java to run the JAR: `java -jar phoebench-cli.jar`.
To use the CLI client in scripts, it is recommended to suppress certain warnings: `java --enable-native-access=ALL_UNNAMED -jar phoebench-cli.jar`, as it will otherwise output warning messages that might trip up your scripts.
+1 -1
View File
@@ -19,7 +19,7 @@ val generateVersion = tasks.register<Task>("serverVersion") {
package com.jaytux.phoebench.client.cli
object CliVersion {
const val VERSION="${rootProject.version}"
const val VERSION="$version"
}
""".trimIndent())
}
+1 -13
View File
@@ -24,7 +24,7 @@ val generateVersion = tasks.register<Task>("clientVersion") {
package com.jaytux.phoebench.client
object ClientVersion {
const val VERSION="${rootProject.version}"
const val VERSION="$version"
}
""".trimIndent())
}
@@ -155,15 +155,3 @@ fun envValue(key: String): String? {
.firstOrNull { it.first == key }?.second
}
}
buildConfig {
sourceSets.getByName("wasmJsMain") {
val serverUrl = envValue("WASM_SERVER_URL") ?:
throw GradleException("MISSING CONFIGURATION: WASM_SERVER_URL. Please set it as environment variable or `.env` variable.")
className("WasmConfig")
packageName("com.jaytux.phoebench.clients")
useKotlinOutput()
buildConfigField("SERVER_URL", serverUrl)
}
}
@@ -181,7 +181,6 @@ fun LoginView(server: String?, error: String?, onSwitchSignup: () -> Unit, onLog
Text("Log in", style = MaterialTheme.typography.headlineMedium)
ServerSelect(serverUrl) { serverUrl = it }
// OutlinedTextField(serverUrl, { serverUrl = it }, Modifier.fillMaxWidth(), label = { Text("Server URL") }, singleLine = true)
OutlinedTextField(username, { username = it }, Modifier.fillMaxWidth(), label = { Text("Username") }, singleLine = true)
OutlinedTextField(password, { password = it }, Modifier.fillMaxWidth(), label = { Text("Password") }, visualTransformation = PasswordVisualTransformation(), singleLine = true)
@@ -213,7 +212,7 @@ fun SignupView(server: String?, error: String?, onSwitchLogin: () -> Unit, onSig
Column(Modifier.padding(5.dp).widthIn(min = 250.dp).width(IntrinsicSize.Min), horizontalAlignment = Alignment.CenterHorizontally) {
Text("Sign up", style = MaterialTheme.typography.headlineMedium)
OutlinedTextField(serverUrl, { serverUrl = it }, Modifier.fillMaxWidth(), label = { Text("Server URL") }, singleLine = true)
ServerSelect(serverUrl) { serverUrl = it }
OutlinedTextField(inviteCode, { inviteCode = it }, Modifier.fillMaxWidth(), label = { Text("Invite code") }, singleLine = true)
OutlinedTextField(username, { username = it }, Modifier.fillMaxWidth(), label = { Text("Username") }, singleLine = true)
@@ -77,6 +77,7 @@ fun ProjectView(id: Uuid, forceBack: () -> Unit) {
Box(Modifier.fillMaxSize().padding(15.dp)) {
ProjectPlotArea(vm)
if(editable) {
if(addOpen) {
CompositionLocalProvider(LocalIndication provides NoFeedbackIndication()) {
Box(Modifier.clickable { addOpen = false }.fillMaxSize())
@@ -123,6 +124,7 @@ fun ProjectView(id: Uuid, forceBack: () -> Unit) {
}
}
}
}
if(editing) ProjectEditDialog(name ?: "Unnamed Project", public, { editing = false }) { name, public ->
vm.update(name, public)
@@ -621,6 +623,7 @@ fun ProjectPlotArea(vm: ProjectVM){
}
else Icon(Lucide.RulerDimensionLine, "Use as baseline")
}
if(editable) {
IconButton({ deletingVersion = lbl }, Modifier.align(Alignment.CenterVertically)) {
Icon(Lucide.Trash, "Delete version")
}
@@ -630,6 +633,7 @@ fun ProjectPlotArea(vm: ProjectVM){
}
}
}
}
Spacer(Modifier.width(15.dp))
LazyColumn(Modifier.weight(0.5f)) {
item { Text("Inputs", style = MaterialTheme.typography.headlineSmall) }
@@ -1,11 +1,13 @@
package com.jaytux.phoebench.clients
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.window.ComposeViewport
import kotlinx.browser.document
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
suspend fun main() {
config = loadConfig()
ComposeViewport(document.body!!) {
App()
}
@@ -6,7 +6,10 @@ import com.jaytux.phoebench.clients.ui.constantServerSelect
import io.ktor.client.*
import io.ktor.client.engine.js.*
import kotlinx.browser.window
import kotlinx.coroutines.await
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import kotlin.uuid.Uuid
@@ -56,7 +59,19 @@ private external fun jsFormat(num: Double): String
actual fun format(f: Float): String = jsFormat(f.toDouble())
@Serializable
data class Config(val server: String)
@OptIn(ExperimentalWasmJsInterop::class)
suspend fun loadConfig(): Config {
val resp = window.fetch("config.json").await()
val text = resp.text().await()
return Json.decodeFromString<Config>(text.toString())
}
lateinit var config: Config
@Composable
actual fun ServerSelect(server: String, onUpdate: (String) -> Unit) {
constantServerSelect(WasmConfig.SERVER_URL)(server, onUpdate)
constantServerSelect(config.server)(server, onUpdate)
}
+1 -1
View File
@@ -22,7 +22,7 @@ val generateVersion = tasks.register<Task>("serverVersion") {
package com.jaytux.phoebench.server
object ServerVersion {
const val VERSION="${rootProject.version}"
const val VERSION="$version"
}
""".trimIndent())
}