commit 07/10/2025

This commit is contained in:
2025-10-07 13:30:27 +07:00
parent 748301a5cb
commit 1c72c7577f
13 changed files with 151 additions and 98 deletions

7
.gitignore vendored
View File

@@ -32,6 +32,7 @@ bin/
.DS_Store
## Soundbank directories ##
/PagingResult/
/SoundBanks/
/SoundbankResult/
PagingResult/
SoundBank/
SoundbankResult/
logs/

View File

@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="github.oshi.core" type="repository">
<properties maven-id="com.github.oshi:oshi-core:6.6.2" />
<properties maven-id="com.github.oshi:oshi-core:6.9.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/github/oshi/oshi-core/6.6.2/oshi-core-6.6.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.14.0/jna-5.14.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.14.0/jna-platform-5.14.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/2.0.13/slf4j-api-2.0.13.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/github/oshi/oshi-core/6.9.0/oshi-core-6.9.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.17.0/jna-5.17.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.17.0/jna-platform-5.17.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/2.0.17/slf4j-api-2.0.17.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

View File

@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="net.java.dev.jna" type="repository">
<properties maven-id="net.java.dev.jna:jna:5.17.0" />
<properties maven-id="net.java.dev.jna:jna:5.18.1" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.17.0/jna-5.17.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.18.1/jna-5.18.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

View File

@@ -1,9 +1,9 @@
<component name="libraryTable">
<library name="tinylog.impl" type="repository">
<properties maven-id="org.tinylog:tinylog-impl:2.6.2" />
<properties maven-id="org.tinylog:tinylog-impl:2.7.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/tinylog/tinylog-impl/2.6.2/tinylog-impl-2.6.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/tinylog/tinylog-api/2.6.2/tinylog-api-2.6.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/tinylog/tinylog-impl/2.7.0/tinylog-impl-2.7.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/tinylog/tinylog-api/2.7.0/tinylog-api-2.7.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.tinylog.Logger
import org.tinylog.provider.ProviderRegistry
import oshi.util.GlobalConfig
import web.WebApp
import java.nio.file.Files
@@ -148,7 +149,7 @@ fun main() {
val _sc = db.soundchannelDB.List.find { it.ip == cmd.ipaddress }
if (_streamer == null) {
// belum create BarixConnection untuk ipaddress ini
Logger.info { "New Streamer Output connection from ${cmd.ipaddress}" }
//Logger.info { "New Streamer Output connection from ${cmd.ipaddress}" }
if (_sc != null) {
val _bc = BarixConnection(_sc.index, _sc.channel, cmd.ipaddress)
_bc.vu = cmd.vu
@@ -188,6 +189,7 @@ fun main() {
audioPlayer.Close()
db.close()
Logger.info { "All services stopped, exiting application." }
ProviderRegistry.getLoggingProvider().shutdown()
})

View File

@@ -100,10 +100,10 @@ class BarixConnection(val index: UInt, var channel: String, val ipaddress: Strin
val chunk = ByteArray(if (bb.remaining() > maxUDPsize) maxUDPsize else bb.remaining())
bb.get(chunk)
while(bufferRemain<chunk.size){
delay(100)
delay(10)
}
udp.send(DatagramPacket(chunk, chunk.size, inet))
delay(5)
delay(1)
} catch (e: Exception) {
cbFail.accept("SendData to $ipaddress:$port failed, message: ${e.message}")
return@launch

View File

@@ -12,6 +12,7 @@ import org.tinylog.Logger
import oshi.SystemInfo
import oshi.hardware.CentralProcessor
import oshi.hardware.GlobalMemory
import oshi.hardware.NetworkIF
import java.nio.file.Files
import java.nio.file.Path
import java.time.LocalDateTime
@@ -39,6 +40,7 @@ class Somecodes {
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")
@@ -263,6 +265,18 @@ class Somecodes {
, (usedMemory.toDouble() / totalMemory * 100))
}
fun GetNetworkStatus(networkname: String) : String{
val networks: List<NetworkIF> = si.hardware.networkIFs.toList()
//TODO cari network yang sesuai dengan networkname
// networks.forEach { net ->
//
// println(net.name+" "+net.displayName+" ")
// net.updateAttributes()
// println("upload: ${SizetoHuman(net.bytesSent)} sent, download: ${SizetoHuman(net.bytesRecv)} received")
// }
return ""
}
/**
* Check if a value is a valid non-blank string.
* @param value The value to check.

View File

@@ -50,31 +50,31 @@ class TCP_Android_Command_Server {
while (isActive) {
if (tcpserver.isClosed) break
try {
tcpserver.accept().use { socket ->
{
val socket = tcpserver.accept()
CoroutineScope(Dispatchers.IO).launch {
if (socket != null) {
// key is IP address only
val key: String = socket.inetAddress.hostAddress
socketMap[key] = socket
Logger.info { "Start communicating with $key" }
socket.getInputStream().let { din ->
{
Logger.info { "Start communicating with IPMT/IPM with IP $key" }
val din = socket.getInputStream()
val dout = socket.getOutputStream()
while (isActive) {
if (din.available() > 0) {
val bb = ByteArray(din.available())
din.read(bb)
// B4A format, 4 bytes di depan adalah size
val str = String(bb, 4, bb.size - 4)
println("Received from $key : $str")
str.split("@").map { it.trim() }.filter { ValidString(it) }
.map { it.uppercase() }.forEach {
.forEach {
process_command(key,it) { reply ->
try {
socket.getOutputStream().write(String_to_Byte_Android(reply))
println("Reply to $key : ${reply.length} bytes")
dout.write(String_to_Byte_Android(reply))
} catch (e: Exception) {
logcb.accept("Failed to send reply to $key, Message : ${e.message}")
}
}
logcb.accept("Failed to send reply to $key, Message : $e")
}
}
}
@@ -85,8 +85,6 @@ class TCP_Android_Command_Server {
}
}
}
}
} catch (ex: Exception) {
logcb.accept("Failed accepting TCP Socket, Message : ${ex.message}")
@@ -109,8 +107,8 @@ class TCP_Android_Command_Server {
*/
private fun String_to_Byte_Android(str: String): ByteArray {
if (ValidString(str)) {
val len = str.length
val bytes = str.toByteArray()
val bytes = str.toByteArray(Charsets.UTF_8)
val len = bytes.size
return ByteBuffer.allocate(len + 4)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt(len)
@@ -128,14 +126,15 @@ class TCP_Android_Command_Server {
*/
private fun process_command(key: String, cmd: String, cb: Consumer<String>) {
Logger.info { "Command from $key : $cmd" }
val parts = cmd.split(";").map { it.trim() }.filter { it.isNotBlank() }.map { it.uppercase() }
val parts = cmd.split(";").map { it.trim() }.filter { it.isNotBlank() }
when (parts[0]) {
"GETLOGIN" -> {
// Android login request
val username = parts.getOrElse(1) { "" }
val password = parts.getOrElse(2) { "" }
if (ValidString(username) && ValidString(password)) {
if (db.userDB.List.any{it.username==username && it.password==password}) {
if (db.userDB.List.any{
it.username==username && it.password==password}) {
val existing = listUserLogin.find { it.ip == key}
if (existing!=null){
existing.username = username
@@ -236,10 +235,14 @@ class TCP_Android_Command_Server {
// pengiriman variabel ke Android
val username = parts.getOrElse(1) { "" }
if (ValidString(username)){
println("Initialize request from $key with username $username")
val userlogin = listUserLogin.find { it.username == username }
if (userlogin != null){
println("User $username found in listUserLogin")
val userdb = db.userDB.List.find { it.username == username }
if (userdb != null){
println("User $username found in userDB")
println(userdb)
val result = StringBuilder()
result.append("ZONE")
userdb.broadcastzones.split(";").map { it.trim() }.filter { it.isNotBlank() }.forEach {
@@ -268,56 +271,59 @@ class TCP_Android_Command_Server {
result.append("MSGTOTAL;").append(VARMESSAGES.size).append("@")
// VAR AP TOTAL
val VARAPTOTAL = mutableListOf<Soundbank>()
val sb_split = userdb.soundbank_tags.split(";").map { it.trim() }.filter { it.isNotBlank() }
sb_split.forEach {
val al_split = userdb.airline_tags.split(";").map { it.trim() }.filter { it.isNotBlank() }
al_split.forEach {
val sb = db.Find_Soundbank_AirplaneName(it).firstOrNull()
if (sb != null) VARAPTOTAL.add(sb)
}
result.append("VARAPTOTAL;").append(VARAPTOTAL.size).append("@")
// VAR CITY TOTAL
val VARCITYTOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val ct_split = userdb.city_tags.split(";").map { it.trim() }.filter { it.isNotBlank() }
ct_split.forEach {
val sb = db.Find_Soundbank_City(it).firstOrNull()
if (sb != null) VARCITYTOTAL.add(sb)
}
result.append("VARCITYTOTAL;").append(VARCITYTOTAL.size).append("@")
// VAR PLACES TOTAL
val VARPLACESTOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val sb = db.Find_Soundbank_Places(it).firstOrNull()
if (sb != null) VARPLACESTOTAL.add(sb)
}
// sb_split.forEach {
// val sb = db.Find_Soundbank_Places(it).firstOrNull()
// if (sb != null) VARPLACESTOTAL.add(sb)
// }
result.append("VARPLACESTOTAL;").append(VARPLACESTOTAL.size).append("@")
// VAR SHALAT TOTAL
val VARSHALATTOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val sb = db.Find_Soundbank_Shalat(it).firstOrNull()
if (sb != null) VARSHALATTOTAL.add(sb)
}
// sb_split.forEach {
// val sb = db.Find_Soundbank_Shalat(it).firstOrNull()
// if (sb != null) VARSHALATTOTAL.add(sb)
// }
result.append("VARSHALATTOTAL;").append(VARSHALATTOTAL.size).append("@")
// VAR SEQUENCE TOTAL
val VARSEQUENCETOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val sb = db.Find_Soundbank_Sequence(it).firstOrNull()
if (sb != null) VARSEQUENCETOTAL.add(sb)
}
// sb_split.forEach {
// val sb = db.Find_Soundbank_Sequence(it).firstOrNull()
// if (sb != null) VARSEQUENCETOTAL.add(sb)
// }
// VAR REASON TOTAL
val VARREASONTOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val sb = db.Find_Soundbank_Reason(it).firstOrNull()
if (sb != null) VARREASONTOTAL.add(sb)
}
// sb_split.forEach {
// val sb = db.Find_Soundbank_Reason(it).firstOrNull()
// if (sb != null) VARREASONTOTAL.add(sb)
// }
result.append("VARREASONTOTAL;").append(VARREASONTOTAL.size).append("@")
// VAR PROCEDURE TOTAL
val VARPROCEDURETOTAL = mutableListOf<Soundbank>()
sb_split.forEach {
val sb = db.Find_Soundbank_Procedure(it).firstOrNull()
if (sb != null) VARPROCEDURETOTAL.add(sb)
}
// sb_split.forEach {
// val sb = db.Find_Soundbank_Procedure(it).firstOrNull()
// if (sb != null) VARPROCEDURETOTAL.add(sb)
// }
result.append("VARPROCEDURETOTAL;").append(VARPROCEDURETOTAL.size).append("@")
// send to sender
cb.accept(result.toString())
println("Result so far: $result")
println("Result size: ${result.length} bytes")
result.clear()
//Append MSG, for Android only Indonesia and English
@@ -359,6 +365,8 @@ class TCP_Android_Command_Server {
result.append("VARPROCEDURE;").append(index).append(";").append(soundbank.TAG).append(";").append(soundbank.Description).append("@")
}
// send to sender
println("Final Result: $result")
println("Final Result size: ${result.length} bytes")
cb.accept(result.toString())
logcb.accept("All variables sent to $key with username $username")

View File

@@ -1840,7 +1840,8 @@ class MariaDB(
"username VARCHAR(100) NOT NULL," +
"password VARCHAR(100) NOT NULL," +
"location VARCHAR(100) NOT NULL," +
"soundbank_tags TEXT NOT NULL,"+ // Comma-separated soundbank tags
"airline_tags TEXT NOT NULL,"+ // Comma-separated soundbank tags
"city_tags TEXT NOT NULL,"+ // Comma-separated soundbank tags
"messagebank_ann_id TEXT NOT NULL,"+ // Comma-separated messagebank announcement index
"broadcastzones TEXT NOT NULL"+ // Comma-separated broadcast zones
")"
@@ -1858,7 +1859,8 @@ class MariaDB(
resultSet.getString("username"),
resultSet.getString("password"),
resultSet.getString("location"),
resultSet.getString("soundbank_tags"),
resultSet.getString("airline_tags"),
resultSet.getString("city_tags"),
resultSet.getString("messagebank_ann_id"),
resultSet.getString("broadcastzones")
)
@@ -1872,13 +1874,14 @@ class MariaDB(
override fun Add(data: UserDB): Boolean {
try {
val statement = connection.prepareStatement("INSERT INTO ${super.dbName} (username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?, ?, ?, ?)")
val statement = connection.prepareStatement("INSERT INTO ${super.dbName} (username, password, location, airline_tags, city_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?, ?,?, ?, ?)")
statement?.setString(1, data.username)
statement?.setString(2, data.password)
statement?.setString(3, data.location)
statement?.setString(4, data.soundbank_tags)
statement?.setString(5, data.messagebank_ann_id)
statement?.setString(6, data.broadcastzones)
statement?.setString(4, data.airline_tags)
statement?.setString(5, data.city_tags)
statement?.setString(6, data.messagebank_ann_id)
statement?.setString(7, data.broadcastzones)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("User added: ${data.username}" as Any)
@@ -1895,15 +1898,16 @@ class MariaDB(
override fun AddAll(data: ArrayList<UserDB>): Boolean {
return try {
connection.autoCommit = false
val sql = "INSERT INTO ${super.dbName} (username, password, location,soundbank_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?, ?, ?, ?)"
val sql = "INSERT INTO ${super.dbName} (username, password, location,airline_tags,city_tags, messagebank_ann_id, broadcastzones) VALUES (?, ?, ?,?, ?, ?, ?)"
val statement = connection.prepareStatement(sql)
for (user in data) {
statement.setString(1, user.username)
statement.setString(2, user.password)
statement.setString(3, user.location)
statement.setString(4, user.soundbank_tags)
statement.setString(5, user.messagebank_ann_id)
statement.setString(6, user.broadcastzones)
statement.setString(4, user.airline_tags)
statement.setString(5, user.city_tags)
statement.setString(6, user.messagebank_ann_id)
statement.setString(7, user.broadcastzones)
statement.addBatch()
}
statement.executeBatch()
@@ -1919,14 +1923,15 @@ class MariaDB(
override fun UpdateByIndex(index: Int, data: UserDB): Boolean {
try {
val statement = connection.prepareStatement("UPDATE ${super.dbName} SET username = ?, password = ?, location = ?, soundbank_tags = ?, messagebank_ann_id = ?, broadcastzones = ? WHERE `index` = ?")
val statement = connection.prepareStatement("UPDATE ${super.dbName} SET username = ?, password = ?, location = ?, airline_tags = ?,city_tags=?, messagebank_ann_id = ?, broadcastzones = ? WHERE `index` = ?")
statement?.setString(1, data.username)
statement?.setString(2, data.password)
statement?.setString(3, data.location)
statement?.setString(4, data.soundbank_tags)
statement?.setString(5, data.messagebank_ann_id)
statement?.setString(6, data.broadcastzones)
statement?.setLong(7, index.toLong())
statement?.setString(4, data.airline_tags)
statement?.setString(5, data.city_tags)
statement?.setString(6, data.messagebank_ann_id)
statement?.setString(7, data.broadcastzones)
statement?.setLong(8, index.toLong())
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("User updated at index $index: ${data.username}" as Any)
@@ -1963,7 +1968,7 @@ class MariaDB(
try {
val sheet = workbook.getSheet("User") ?: throw Exception("No sheet named 'User' found")
val headerRow = sheet.getRow(0) ?: throw Exception("No header row found")
val headers = arrayOf("Index", "username", "password", "location", "soundbank_tags", "messagebank_ann_id", "broadcastzones")
val headers = arrayOf("Index", "username", "password", "location", "airline_tags", "city_tags", "messagebank_ann_id", "broadcastzones")
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.getCell(colIndex) ?: throw Exception("Header '$header' not found")
if (cell.stringCellValue != header) throw Exception("Header '$header' not found")
@@ -1977,10 +1982,11 @@ class MariaDB(
val username = row.getCell(1)?.stringCellValue ?: continue
val password = row.getCell(2)?.stringCellValue ?: continue
val location = row.getCell(3)?.stringCellValue ?: continue
val soundbank_tags = row.getCell(4)?.stringCellValue ?: continue
val messagebank_ann_id = row.getCell(5)?.stringCellValue ?: continue
val broadcastzones = row.getCell(6)?.stringCellValue ?: continue
val user = UserDB(0u, username, password, location, soundbank_tags, messagebank_ann_id, broadcastzones)
val airline_tags = row.getCell(4)?.stringCellValue ?: continue
val city_tags = row.getCell(5)?.stringCellValue ?: continue
val messagebank_ann_id = row.getCell(6)?.stringCellValue ?: continue
val broadcastzones = row.getCell(7)?.stringCellValue ?: continue
val user = UserDB(0u, username, password, location, airline_tags,city_tags, messagebank_ann_id, broadcastzones)
_userList.add(user)
}
return AddAll(_userList)
@@ -1997,7 +2003,7 @@ class MariaDB(
val workbook = XSSFWorkbook()
val sheet = workbook.createSheet("User")
val headerRow = sheet.createRow(0)
val headers = arrayOf("Index", "username", "password", "location", "soundbank_tags", "messagebank_ann_id", "broadcastzones")
val headers = arrayOf("Index", "username", "password", "location", "airline_tags","city_tags", "messagebank_ann_id", "broadcastzones")
for ((colIndex, header) in headers.withIndex()) {
val cell = headerRow.createCell(colIndex)
cell.setCellValue(header)
@@ -2009,9 +2015,10 @@ class MariaDB(
row.createCell(1).setCellValue(resultSet.getString("username"))
row.createCell(2).setCellValue(resultSet.getString("password"))
row.createCell(3).setCellValue(resultSet.getString("location"))
row.createCell(4).setCellValue(resultSet.getString("soundbank_tags"))
row.createCell(5).setCellValue(resultSet.getString("messagebank_ann_id"))
row.createCell(6).setCellValue(resultSet.getString("broadcastzones"))
row.createCell(4).setCellValue(resultSet.getString("airline_tags"))
row.createCell(5).setCellValue(resultSet.getString("city_tags"))
row.createCell(6).setCellValue(resultSet.getString("messagebank_ann_id"))
row.createCell(7).setCellValue(resultSet.getString("broadcastzones"))
}
for (i in headers.indices) {
sheet.autoSizeColumn(i)

View File

@@ -1,4 +1,11 @@
package database
@Suppress("unused")
data class UserDB(var index: UInt, var username: String, var password: String, var location: String, var soundbank_tags: String, var messagebank_ann_id: String, var broadcastzones: String)
data class UserDB(var index: UInt, var username: String, var password: String, var location: String, var airline_tags: String, var city_tags: String, var messagebank_ann_id: String, var broadcastzones: String){
override fun toString(): String {
return "UserDB(index=$index, username='$username', location='$location', airline_tags='$airline_tags', city_tags='$city_tags', messagebank_ann_id='$messagebank_ann_id', broadcastzones='$broadcastzones')"
}
}

View File

@@ -0,0 +1,2 @@
# gak mau lihat log javalin
org.slf4j.simpleLogger.defaultLogLevel=error

10
src/tinylog.properties Normal file
View File

@@ -0,0 +1,10 @@
writer1 = console
writer1.level = info
writer1.format = {date:dd/MM/yyyy HH:mm:ss} {class}.{method}(): {message}
writer2 = rolling file
writer2.format = {date:dd/MM/yyyy HH:mm:ss} {class}.{method}(): {message}
writer2.file = logs/{date:yyyy}/{date:MM}/{date:dd}.log
writer2.level = info
autoshutdown = false # optional, default: true

View File

@@ -52,6 +52,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
}
fun Start() {
app = Javalin.create { config ->
config.useVirtualThreads = true
config.staticFiles.add("/webpage")
@@ -125,6 +126,7 @@ class WebApp(val listenPort: Int, val userlist: List<Pair<String, String>>) {
"getNetworkStatus" -> {
// TODO Get Network status
Somecodes.GetNetworkStatus("")
SendReply(wsMessageContext, cmd.command, "OK")
}