commit 20/08/2025

This commit is contained in:
2025-08-20 16:42:06 +07:00
parent 4f0a7a1560
commit 0c84449b77
28 changed files with 966 additions and 42 deletions

View File

@@ -1,7 +1,7 @@
import audio.AudioPlayer
import content.ContentCache
import org.tinylog.Logger
import web.WebApp
fun main() {
@@ -9,5 +9,12 @@ fun main() {
val audioPlayer = AudioPlayer(44100) // 44100 Hz sampling rate
audioPlayer.InitAudio(1)
val content = ContentCache()
val web = WebApp(3030,
listOf(
Pair("admin", "password"),
Pair("user", "password")
)
)
web.Start()
}

View File

@@ -1,5 +1,8 @@
package codes
import oshi.SystemInfo
import oshi.hardware.CentralProcessor
import oshi.hardware.GlobalMemory
import java.nio.file.Files
import java.nio.file.Path
@@ -7,6 +10,45 @@ import java.nio.file.Path
@Suppress("unused")
class Somecodes {
companion object {
val si = SystemInfo()
val processor: CentralProcessor = si.hardware.processor
val memory : GlobalMemory = si.hardware.memory
const val KB_threshold = 1024.0
const val MB_threshold = KB_threshold * 1024.0
const val GB_threshold = MB_threshold * 1024.0
const val TB_threshold = GB_threshold * 1024.0
/**
* Converts a size in bytes to a human-readable format.
* @param size Size in bytes.
* @return A string representing the size in a human-readable format.
*/
fun SizetoHuman(size: Long): String {
return when {
size < KB_threshold -> "${size}B"
size < MB_threshold -> String.format("%.2f KB", size / KB_threshold)
size < GB_threshold -> String.format("%.2f MB", size / MB_threshold)
size < TB_threshold -> String.format("%.2f GB", size / GB_threshold)
else -> String.format("%.2f TB", size / TB_threshold)
}
}
fun getMemoryUsage() : String{
val totalMemory = memory.total
val availableMemory = memory.available
val usedMemory = totalMemory - availableMemory
return String.format("Total: %s, Used: %s, Available: %s, Usage: %.2f%%",
SizetoHuman(totalMemory),
SizetoHuman(usedMemory),
SizetoHuman(availableMemory)
, (usedMemory.toDouble() / totalMemory * 100))
}
fun ValidString(value: Any) : Boolean {
return value is String && value.isNotBlank()
}

View File

@@ -1,5 +1,8 @@
package database
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.mariadb.jdbc.Connection
import org.tinylog.Logger
import java.sql.DriverManager
@@ -46,19 +49,17 @@ class MariaDB (
Logger.info("Connected to MariaDB" as Any)
connected = true
val loadthread = Thread {
// Load soundbank and messagebank lists
Reload_Messagebank()
Logger.info { "Messagebank loaded" }
Reload_Soundbank()
Logger.info { "Soundbank loaded" }
runBlocking {
withContext(Dispatchers.IO){
Reload_Messagebank()
Logger.info { "Messagebank loaded" }
Reload_Soundbank()
Logger.info { "Soundbank loaded" }
}
}
loadthread.name = "LoadMariaDBThread"
loadthread.isDaemon = true
loadthread.start()
loadthread.join()
Logger.info { "Loading MariaDB completed" }
Logger.info { "Soundbank count: ${SoundbankList.size}" }
Logger.info { "Messagebank count: ${MessagebankList.size}" }

145
src/web/WebApp.kt Normal file
View File

@@ -0,0 +1,145 @@
package web
import codes.Somecodes
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import io.javalin.Javalin
import io.javalin.apibuilder.ApiBuilder.before
import io.javalin.apibuilder.ApiBuilder.get
import io.javalin.apibuilder.ApiBuilder.path
import io.javalin.apibuilder.ApiBuilder.post
import io.javalin.apibuilder.ApiBuilder.ws
import io.javalin.http.Context
@Suppress("unused")
class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
var app : Javalin? = null
private val objectmapper = jacksonObjectMapper()
fun Start() {
app = Javalin.create {
config ->
config.useVirtualThreads = true
config.staticFiles.add("/webpage")
config.router.apiBuilder {
path("/"){
get { ctx ->
// Serve the main page
ctx.sessionAttribute("user", null) // Clear user session
ctx.redirect("login.html")
}
}
path("login.html"){
post{ it ->
// get username and password from form
val username = it.formParam("username")
val password = it.formParam("password")
if (username == null || password == null) {
it.status(400).result("Username and password are required")
return@post
}
// Check if user exists in userlist
val user = userlist.find { it.first == username && it.second == password }
if (user == null) {
it.status(401).result("Invalid username or password")
return@post
}
// Set user session
it.sessionAttribute("user", user.first)
println("User ${user.first} logged in")
// Redirect to home page
it.redirect("home.html")
}
}
path("home.html") {
before { CheckUsers(it) }
ws("/ws") { it ->
// WebSocket endpoint for home
it.onClose {
// TODO Handle WebSocket close event
println("WebSocket closed: ${it.session.remoteAddress}")
}
it.onMessage {
try{
val cmd = objectmapper.readValue(it.message(), WebsocketCommand::class.java)
when (cmd.command) {
"getCPUStatus" ->{
//TODO Get CPU status
it.send(objectmapper.writeValueAsString(WebsocketReply(cmd.command,"OK")))
}
"getMemoryStatus" ->{
// TODO Get Memory status
it.send(objectmapper.writeValueAsString(WebsocketReply(cmd.command, Somecodes.getMemoryUsage())))
}
"getDiskStatus" ->{
// TODO Get Disk status
it.send(objectmapper.writeValueAsString(WebsocketReply(cmd.command,"OK")))
}
"getNetworkStatus" ->{
// TODO Get Network status
it.send(objectmapper.writeValueAsString(WebsocketReply(cmd.command,"OK")))
}
else -> {
it.send(objectmapper.writeValueAsString(WebsocketReply("error", "Unknown command: ${cmd.command}")))
}
}
} catch (e: Exception){
println("Error processing WebSocket message: ${e.message}")
}
}
it.onConnect {
// TODO Handle WebSocket connect event
println("WebSocket connected: ${it.session.remoteAddress}")
}
}
}
path("soundbank.html") {
before {CheckUsers(it)}
}
path("messagebank.html") {
before { CheckUsers(it) }
}
path("language.html") {
before { CheckUsers(it) }
}
path("log.html") {
before { CheckUsers(it) }
}
path("setting.html") {
before { CheckUsers(it) }
}
path("timer.html") {
before { CheckUsers(it) }
}
}
}.start(listenPort)
}
fun CheckUsers(ctx: Context){
println("Checking user session at ${ctx.req().requestURI}")
val user = ctx.sessionAttribute<String?>("user")
if (user == null) {
println("User not logged in, redirecting to login page")
ctx.redirect("login.html")
}
println("User is logged in: $user")
val foundUser = userlist.find { it.first == user }
if (foundUser==null) {
println("User not found in user list, redirecting to login page")
ctx.redirect("login.html")
} else {
println("User found: $user")
}
}
fun Stop(){
app?.stop()
}
}

View File

@@ -0,0 +1,4 @@
package web
@Suppress("unused")
data class WebsocketCommand (val command: String, val data: String)

View File

@@ -0,0 +1,4 @@
package web
@Suppress("unused")
data class WebsocketReply (val reply: String, val data: String)