package io.gitlab.jfronny.inceptum.gtk.util import io.gitlab.jfronny.commons.OSUtils import io.gitlab.jfronny.inceptum.common.Utils import java.io.IOException import java.nio.file.Files import java.nio.file.Path import java.util.regex.Pattern object Memory { const val KB: Long = 1024 const val MB = KB * 1024 const val GB = MB * 1024 private val impl = when (OSUtils.TYPE) { OSUtils.Type.LINUX -> LinuxMI OSUtils.Type.WINDOWS -> WindowsMI OSUtils.Type.MAC_OS -> MacOsMI } private val totalMemory by lazy { impl.getTotalMemory() } val maxMBForInstance: Long get() = (totalMemory / MB - 1024).coerceAtLeast(1024) private interface MI { fun getTotalMemory(): Long } private object LinuxMI : MI { override fun getTotalMemory(): Long { try { Files.lines(Path.of("/proc/meminfo")).use { stream -> val memTotal = stream .filter { s: String -> s.startsWith("MemTotal:") } .map { s: String -> s.substring("MemTotal:".length) } .map { obj: String -> obj.trim { it <= ' ' } } .findFirst() return if (memTotal.isPresent()) { parseDecimalMemorySizeToBinary(memTotal.get()) } else { Utils.LOGGER.error("Could not find total memory") 32 * GB } } } catch (e: IOException) { Utils.LOGGER.error("Could not get total memory", e) return 32 * GB } } // Taken from oshi private val BYTES_PATTERN = Pattern.compile("(\\d+) ?([kKMGT]?B?).*") private val WHITESPACES = Pattern.compile("\\s+") private fun parseDecimalMemorySizeToBinary(size: String): Long { var mem = WHITESPACES.split(size) if (mem.size < 2) { // If no spaces, use regexp val matcher = BYTES_PATTERN.matcher(size.trim { it <= ' ' }) if (matcher.find() && matcher.groupCount() == 2) { mem = arrayOfNulls(2) mem[0] = matcher.group(1) mem[1] = matcher.group(2) } } var capacity = parseLongOrDefault(mem[0], 0L) if (mem.size == 2 && mem[1]!!.length > 1) { when (mem[1]!![0]) { 'T' -> capacity = capacity shl 40 'G' -> capacity = capacity shl 30 'M' -> capacity = capacity shl 20 'K', 'k' -> capacity = capacity shl 10 else -> {} } } return capacity } private fun parseLongOrDefault(s: String, defaultLong: Long): Long = try { s.toLong() } catch (e: NumberFormatException) { defaultLong } } private object WindowsMI : MI { override fun getTotalMemory(): Long { return 32 * GB // This is currently unsupported, but any implementations by Windows user using panama are welcome } } private object MacOsMI : MI { override fun getTotalMemory(): Long { return 32 * GB // This is currently unsupported, but any implementations by MacOS user using panama are welcome } } }