Files
AAS_NewGeneration/src/codes/Somecodes.kt
2025-09-25 15:54:33 +07:00

380 lines
14 KiB
Kotlin

package codes
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import content.ScheduleDay
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import oshi.SystemInfo
import oshi.hardware.CentralProcessor
import oshi.hardware.GlobalMemory
import java.nio.file.Files
import java.nio.file.Path
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.function.Consumer
import kotlin.io.path.name
@Suppress("unused")
class Somecodes {
companion object {
val current_directory : String = System.getProperty("user.dir")
val SoundbankResult_directory : Path = Path.of(current_directory,"SoundbankResult")
val PagingResult_directory : Path = Path.of(current_directory,"PagingResult")
val si = SystemInfo()
val processor: CentralProcessor = si.hardware.processor
val memory : GlobalMemory = si.hardware.memory
val datetimeformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")
val dateformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
val dateformat2: DateTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy")
val timeformat1: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm:ss")
val timeformat2: DateTimeFormatter = DateTimeFormatter.ofPattern("hh:mm")
val filenameformat: DateTimeFormatter = DateTimeFormatter.ofPattern("ddMMyyyy_HHmmss")
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
val objectmapper = jacksonObjectMapper()
// regex for getting ann_id from Message, which is the number inside []
private val ann_id_regex = Regex("\\[(\\d+)]")
/**
* Check if a string is a valid number.
*/
fun IsNumber(value: String) : Boolean {
return value.toIntOrNull() != null
}
/**
* Check if a string is alphabetic (contains only letters).
*/
fun IsAlphabethic(value: String) : Boolean {
return value.all { it.isLetter() }
}
/**
* Extract ANN ID from a message string.
* The ANN ID is expected to be a number enclosed in square brackets (e.g., "[123]").
* @param message The message string to extract the ANN ID from.
* @return The extracted ANN ID as an integer, or -1 if not found or invalid.
*/
fun Get_ANN_ID(message: String) : Int {
val matchResult = ann_id_regex.find(message)
return matchResult?.groups?.get(1)?.value?.toInt() ?: -1
}
/**
* Convert an object to a JSON string.
* @param data The object to convert.
* @return A JSON string representation of the object, or "{}" if conversion fails.
*/
fun toJsonString(data: Any) : String {
return try {
objectmapper.writeValueAsString(data)
} catch (e: Exception){
"{}"
}
}
/**
* Convert a JSON string to an object of the specified class.
* @param json The JSON string to convert.
* @param clazz The class of the object to convert to.
* @return An object of the specified class, or null if conversion fails.
*/
fun <T> fromJsonString(json: String, clazz: Class<T>) : T? {
return try {
objectmapper.readValue(json, clazz)
} catch (e: Exception){
null
}
}
/**
* Convert a JSON string to a JsonNode.
* @param data The JSON string to convert.
* @return A JsonNode representation of the JSON string, or empty JsonNode if conversion fails.
*/
fun toJsonNode(data: String) : JsonNode {
return try {
objectmapper.readTree(data)
} catch (e: Exception){
objectmapper.createObjectNode()
}
}
/**
* List all audio files (.mp3 and .wav) in the specified directory and its subdirectories.
* Only files larger than 1KB are included.
* @param dir The directory to search in (default is the current working directory).
* @return A list of absolute paths to the audio files found.
*/
fun ListAudioFiles(dir: String = current_directory) : List<String>{
return try{
// find all files that ends with .mp3 or .wav
// and find them recursively
val p = Path.of(dir)
if (Files.exists(p) && Files.isDirectory(p)){
Files.walk(p)
// cari file regular saja
.filter { Files.isRegularFile(it)}
// size lebih dari 1KB
.filter { Files.size(it) > 1024}
// extension .mp3 atau .wav
.filter { it.name.endsWith(".mp3",true) || it.name.endsWith(".wav",true) }
.map { it.toAbsolutePath().toString() }
.toList()
} else throw Exception()
} catch (_ : Exception){
emptyList()
}
}
/**
* 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)
}
}
/**
* Get Disk usage using OSHI library.
* @param path The path to check disk usage, defaults to the current working directory.
* @return A string representing the disk usage of the file system in a human-readable format.
*/
fun getDiskUsage(path: String = current_directory) : String {
return try{
val p = Path.of(path).toFile()
if (p.exists() && p.isDirectory){
val total = p.totalSpace
val free = p.freeSpace
val used = total - free
String.format("Total: %s, Used: %s, Free: %s, Usage: %.2f%%",
SizetoHuman(total),
SizetoHuman(used),
SizetoHuman(free),
(used.toDouble() / total * 100)
)
} else throw Exception()
} catch (_ : Exception){
"N/A"
}
}
/**
* Get CPU usage using OSHI library.
* @param cb A callback function that receives the CPU usage as a string.
*/
fun getCPUUsage(cb : Consumer<String>){
CoroutineScope(Dispatchers.Default).launch {
val prev = processor.systemCpuLoadTicks
delay(1000)
val current = processor.systemCpuLoadTicks
fun delta(t: CentralProcessor.TickType) = current[t.index] - prev[t.index]
val idle = delta(CentralProcessor.TickType.IDLE) + delta(CentralProcessor.TickType.IOWAIT)
val busy = delta(CentralProcessor.TickType.USER) + delta(CentralProcessor.TickType.SYSTEM) +
delta(CentralProcessor.TickType.NICE) + delta(CentralProcessor.TickType.IRQ) +
delta(CentralProcessor.TickType.SOFTIRQ)+ delta(CentralProcessor.TickType.STEAL)
val total = idle + busy
val usage = if (total > 0) {
(busy.toDouble() / total) * 100
} else {
0.0
}
cb.accept(String.format("%.2f%%", usage))
}
}
/**
* Get RAM usage using OSHI library.
* @return A string representing the total, used, and available memory in a human-readable format.
*/
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))
}
/**
* Check if a value is a valid non-blank string.
* @param value The value to check.
* @return True if the value is a non-blank string, false otherwise.
*/
fun ValidString(value: Any) : Boolean {
return value is String && value.isNotBlank()
}
/**
* Check if a string is a valid file path and the file exists.
* @param value The string to check.
* @return True if the string is a valid file path, false otherwise.
*/
fun ValidFile(value : String) : Boolean {
if (value.isNotBlank()){
return Files.exists(Path.of(value))
}
return false
}
/**
* Check if a string is a valid date in the format "dd/MM/yyyy".
* @param value The string to check.
* @return True if the string is a valid date, false otherwise.
*/
fun ValidDate(value: String): Boolean{
return try{
if (ValidString(value)){
dateformat1.parse(value)
true
} else throw Exception()
} catch (_: Exception){
false
}
}
/**
* Check if a string is a valid IPv4 address.
* @param value The string to check.
* @return True if the string is a valid IPv4 address, false otherwise.
*/
fun ValidIPV4(value: String): Boolean{
return try{
if (ValidString(value)){
val parts = value.split(".")
if (parts.size != 4) return false
for (part in parts){
val num = part.toInt()
if (num !in 0..255) return false
}
true
} else throw Exception()
} catch (_: Exception){
false
}
}
/**
* Check if a string is a valid date in the format "dd-MM-yyyy".
* This format is used for log HTML files.
* @param value The string to check.
* @return True if the string is a valid date, false otherwise.
*/
fun ValiDateForLogHtml(value: String): Boolean{
return try{
if (ValidString(value)){
dateformat2.parse(value)
true
} else throw Exception()
} catch (_: Exception){
false
}
}
/**
* Check if a string is a valid time in the format "hh:mm:ss".
* @param value The string to check.
* @return True if the string is a valid time, false otherwise.
*/
fun ValidTime(value: String): Boolean{
return try{
if (ValidString(value)){
timeformat1.parse(value)
true
} else throw Exception()
} catch (_: Exception){
false
}
}
/**
* Check if a string is a valid schedule time in the format "HH:mm".
* @param value The string to check.
* @return True if the string is a valid schedule time, false otherwise.
*/
fun ValidScheduleTime(value: String): Boolean{
// format HH:mm
try {
if (ValidString(value)){
timeformat2.parse(value)
return true
}
} catch (_ : Exception){
}
return false
}
/**
* Find a schedule day by its name.
* @param value The name of the schedule day to find.
* @return The name of the schedule day if found, null otherwise.
*/
fun FindScheduleDay(value: String) : String? {
val sd = ScheduleDay.entries.find { sd -> sd.name == value }
return sd?.name
}
/**
* Check if a string is a valid schedule day or a valid date.
* A valid schedule day is either one of the ScheduleDay enum names or a date in the format "dd/MM/yyyy".
* @param value The string to check.
* @return True if the string is a valid schedule day or date, false otherwise.
*/
fun ValidScheduleDay(value: String) : Boolean {
if (ValidString(value)){
// check if value is one of ScheduleDay enum name
if (FindScheduleDay(value) != null){
return true
}
// check if value is in format dd/MM/yyyy
return ValidDate(value)
}
return false
}
/**
* Generate a WAV file name with the current date and time.
* The file name format is: [prefix]_ddMMyyyy_HHmmss_[postfix].wav
* @param prefix An optional prefix to add before the date and time.
* @param postfix An optional postfix to add after the date and time.
* @return A string representing the generated WAV file name.
*/
fun Make_WAV_FileName(prefix: String, postfix: String) : String{
val sb = StringBuilder()
if (prefix.isNotEmpty()){sb.append(prefix).append("_")}
sb.append(filenameformat.format(LocalDateTime.now()))
if (postfix.isNotEmpty()){sb.append("_").append(postfix)}
sb.append(".wav")
return sb.toString()
}
}
}