Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import app.simplecloud.droplet.serverhost.runtime.config.environment.Environment
import app.simplecloud.droplet.serverhost.runtime.config.environment.EnvironmentConfigGenerator
import app.simplecloud.droplet.serverhost.runtime.config.environment.EnvironmentStartConfig
import app.simplecloud.droplet.serverhost.runtime.launcher.ServerHostStartCommand
import java.io.File
import java.nio.file.Paths
import kotlin.io.path.absolutePathString

Expand All @@ -20,7 +21,7 @@ object DefaultEnvironmentConfigGenerator : EnvironmentConfigGenerator {
"-Xmx%MAX_MEMORY%M",
"-Dcom.mojang.eula.agree=true",
"-cp",
"${libs}/*:%SERVER_FILE%",
"${libs}/*${File.pathSeparator}%SERVER_FILE%",
"%MAIN_CLASS%",
"nogui"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app.simplecloud.droplet.serverhost.runtime.process
import app.simplecloud.droplet.serverhost.runtime.util.ProcessDirectory
import java.nio.file.Path
import java.util.*
import java.util.concurrent.atomic.AtomicReference
import kotlin.io.path.absolutePathString

object ProcessFinder {
Expand All @@ -23,19 +24,41 @@ object ProcessFinder {
}

fun findHighestExecutableProcess(handle: ProcessHandle, executable: String): Optional<ProcessHandle> {
var returned = Optional.empty<ProcessHandle>()
// Check the current handle first
val currentCommand = handle.info().command().orElse("").lowercase()
if (currentCommand.contains(executable.lowercase())) {
return Optional.of(handle)
}

val found = AtomicReference<Optional<ProcessHandle>>(Optional.empty())

// Check immediate children
handle.children().forEach { child ->
if (!returned.isEmpty) return@forEach
if (ProcessInfo.of(child).getCommand().lowercase().startsWith(executable)) {
returned = Optional.of(child)
if (found.get().isPresent) return@forEach

val command = child.info().command().orElse("").lowercase()

if (command.contains(executable.lowercase())) {
found.set(Optional.of(child))
}
}
if (!returned.isEmpty) return returned

// Return if we found a match in the first pass
if (found.get().isPresent) {
return found.get()
}

// Recursive search through children
handle.children().forEach { child ->
if (!returned.isEmpty) return@forEach
returned = findHighestExecutableProcess(child, executable)
if (found.get().isPresent) return@forEach

val childResult = findHighestExecutableProcess(child, executable)
if (childResult.isPresent) {
found.set(childResult)
}
}
return returned

return found.get()
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,96 @@
package app.simplecloud.droplet.serverhost.runtime.process

class WindowsProcessInfo(private val pid: Long) : ProcessInfo {

override fun getCommand(): String {
return ProcessHandle.of(pid).get().info().commandLine().get()
return ProcessHandle.of(pid)
.map { it.info().command().orElse("") }
.orElse("")
}

override fun getRamAndCpuPercent(): Pair<Double, Double> {
TODO("Not yet implemented")
try {
val memCmd = Runtime.getRuntime().exec(
arrayOf(
"cmd.exe",
"/c",
"tasklist /FI \"PID eq $pid\" /FO CSV /NH /V"
)
)

var memKB: Long
memCmd.waitFor()
memCmd.inputReader(Charsets.UTF_8).use { reader ->
val output = reader.readText()
memKB = output.split(",")
.getOrNull(4)
?.trim()
?.removeSurrounding("\"")
?.replace(Regex("[^0-9]"), "") // Remove any non-numeric characters
?.toLongOrNull() ?: 0L

}

val cpuCmd = Runtime.getRuntime().exec(
arrayOf(
"cmd.exe",
"/c",
"tasklist /FI \"PID eq $pid\" /FO CSV /NH /V"
)
)

var cpuPercent = 0.0
cpuCmd.waitFor()
cpuCmd.inputReader(Charsets.UTF_8).use { reader ->
val output = reader.readText()
val cpuTimeStr = output.split(",")
.getOrNull(8)
?.trim()
?.removeSurrounding("\"")
?: "00:00:00"

// Convert HH:MM:SS to seconds
val parts = cpuTimeStr.split(":")
val totalSeconds = if (parts.size == 3) {
(parts[0].toLongOrNull() ?: 0L) * 3600L +
(parts[1].toLongOrNull() ?: 0L) * 60L +
(parts[2].toLongOrNull() ?: 0L)
} else {
0L
}

val uptime = ProcessHandle.of(pid)
.map { handle ->
handle.info().startInstant()
.map { start ->
java.time.Duration.between(start, java.time.Instant.now()).seconds
}
.orElse(1L)
}
.orElse(1L)
.coerceAtLeast(1L)

val processors = Runtime.getRuntime().availableProcessors()
cpuPercent = (totalSeconds.toDouble() / uptime.toDouble() * 100.0 * processors)
.coerceIn(0.0, 100.0)
}

val totalMemBytes = when (val osBean = java.lang.management.ManagementFactory.getOperatingSystemMXBean()) {
is com.sun.management.OperatingSystemMXBean -> osBean.totalPhysicalMemorySize
else -> Runtime.getRuntime().maxMemory()
}

val memBytes = memKB * 1024L
val memPercent = (memBytes.toDouble() / totalMemBytes.toDouble() * 100.0)
.coerceIn(0.0, 100.0)

return Pair(memPercent, cpuPercent)
} catch (e: Exception) {
return Pair(0.0, 0.0)
}
}

override fun asHandle(): ProcessHandle {
return ProcessHandle.of(pid).get()
}

}