commit 06/10/2025

This commit is contained in:
2025-10-06 08:30:09 +07:00
parent 20dbc12b02
commit cf69c72f3c
9 changed files with 97 additions and 81 deletions

View File

@@ -23,6 +23,8 @@ lateinit var audioPlayer: AudioPlayer
val StreamerOutputs: MutableMap<String, BarixConnection> = HashMap()
lateinit var udpreceiver: UDPReceiver
const val version = "0.0.2 (23/09/2025)"
// AAS 64 channels
const val max_channel = 64
// dipakai untuk pilih voice type, bisa diganti via web nanti
var selected_voice = VoiceType.VOICE_1.name
@@ -91,7 +93,7 @@ fun main() {
val barixserver = TCP_Barix_Command_Server()
barixserver.StartTcpServer { cmd ->
Logger.info { cmd }
//Logger.info { cmd }
val _streamer = StreamerOutputs[cmd.ipaddress]
val _sc = db.soundchannelDB.List.find { it.ip == cmd.ipaddress }
if (_streamer == null) {
@@ -103,7 +105,8 @@ fun main() {
_bc.bufferRemain = cmd.buffremain
_bc.statusData = cmd.statusdata
StreamerOutputs[cmd.ipaddress] = _bc
}
Logger.info { "Created new Streamer Output for channel ${_sc.channel} with IP ${cmd.ipaddress}" }
} else Logger.warn { "soundChannelDB doesn't have soundchannel with IP ${cmd.ipaddress}" }
} else {
// sudah ada, update data

View File

@@ -39,16 +39,24 @@ class MainExtension01 {
*/
fun AllBroadcastZonesValid(bz: List<String>): Boolean {
if (bz.isNotEmpty()) {
println("StreamerOutputs: $StreamerOutputs")
val validchannels = bz
// check apakah tiap zone ada di database broadcast zones
.filter { z1 ->
db.broadcastDB.List.find { z2 -> z2.SoundChannel == z1 } != null
println("Checking broadcast zone $z1")
val xx = db.broadcastDB.List.find { z2 -> z2.description == z1 }
println("Found in DB: $xx")
xx != null
}
// check apakah tiap zone ada di SoundChannelList dan Online
.filter { z3 ->
StreamerOutputs.any { sc -> sc.value.channel == z3 && sc.value.isOnline() }
println("Checking if zone $z3 is in StreamerOutputs and online")
val xx = StreamerOutputs.values.find { it.channel == z3 }
println("Is online: $xx")
xx!= null
}
println("Valid channels: $validchannels")
// kalau jumlah valid channel sama dengan jumlah broadcast zone, berarti semua valid
return validchannels.size == bz.size
}
@@ -484,6 +492,7 @@ class MainExtension01 {
fun Read_Queue_Paging(){
db.queuepagingDB.Get()
for (qp in db.queuepagingDB.List) {
println("Processing QueuePaging $qp")
if (qp.BroadcastZones.isNotBlank()) {
val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)) {
@@ -615,10 +624,14 @@ class MainExtension01 {
fun Read_Queue_Table(){
db.queuetableDB.Get()
db.queuetableDB.List.forEach { qa ->
println("Processing QueueTable $qa")
if (qa.BroadcastZones.isNotEmpty()) {
val zz = qa.BroadcastZones.split(";")
println("Broadcast zones: $zz")
if (AllBroadcastZonesValid(zz)) {
println("All broadcast zones valid")
if (AllBroadcastZoneIdle(zz)) {
println("All broadcast zones idle")
if (qa.Type == "SOUNDBANK") {
val variables = Get_Soundbank_Data(qa.SB_TAGS)
val languages = qa.Language.split(";")

View File

@@ -9,11 +9,11 @@ import java.util.function.Consumer
@Suppress("unused")
class TCP_Barix_Command_Server {
private var tcpserver: ServerSocket? = null
private var job: Job? = null
lateinit var tcpserver: ServerSocket
lateinit var job: Job
private val socketMap = mutableMapOf<String, Socket>()
private val regex = """\$\\"STATUSBARIX;(\d+);(\d+);?(\d)?\\"$"""
private val regex = """STATUSBARIX;(\d+);(\d+);?(\d)?"""
private val pattern = Regex(regex)
/**
@@ -27,25 +27,23 @@ class TCP_Barix_Command_Server {
val tcp = ServerSocket(port)
tcpserver = tcp
job = CoroutineScope(Dispatchers.IO).launch {
Logger.info { "TCP server started" }
Logger.info { "TCP StreamerOutput server started on port $port" }
while (isActive) {
if (tcpserver?.isClosed == true) break
if (tcpserver.isClosed) break
try {
tcpserver?.accept().use { socket ->
{
CoroutineScope(Dispatchers.Main).launch {
if (socket != null) {
val key : String = socket.inetAddress.hostAddress+":"+socket.port
val socket = tcpserver.accept()
CoroutineScope(Dispatchers.IO).launch {
val key : String = socket.inetAddress.hostAddress
socketMap[key] = socket
Logger.info { "Start communicating with $key" }
socket.getInputStream().use { din ->
{
Logger.info { "Start communicating with Streamer Output with IP : $key" }
val din = socket.getInputStream()
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)
val str = String(bb, 4, bb.size - 4)
if (ValidString(str)) {
// Valid command from Barix is in format $"STATUSBARIX;VU;BuffRemain;StatusData"$
pattern.find(str)?.let { matchResult ->
@@ -56,7 +54,7 @@ class TCP_Barix_Command_Server {
buffremain.toInt(),
statusdata.toIntOrNull() ?: 0
)
Logger.info { "Received valid command from $key : $status" }
//Logger.info { "Received valid command from $key : $status" }
cb.accept(status)
} ?: run {
Logger.warn { "Invalid command format from $key : $str" }
@@ -64,15 +62,10 @@ class TCP_Barix_Command_Server {
}
}
}
}
}
Logger.info { "Finished communicating with $key" }
Logger.info { "Finished communicating with Streamer Output with IP $key" }
socketMap.remove(key)
}
}
}
}
} catch (ex: Exception) {
Logger.error { "Failed accepting TCP Socket, Message : ${ex.message}" }
@@ -94,20 +87,18 @@ class TCP_Barix_Command_Server {
*/
fun StopTcpCommand(): Boolean {
try {
tcpserver?.close()
tcpserver.close()
runBlocking {
socketMap.values.forEach {
it.close()
}
socketMap.clear()
job?.join()
job.join()
}
Logger.info { "StopTcpCommand success" }
return true
} catch (e: Exception) {
Logger.error { "Failed to StopTcpServer, Message : ${e.message}" }
} finally {
tcpserver = null
}
return false
}

View File

@@ -27,8 +27,8 @@ import kotlin.io.path.absolutePathString
@Suppress("unused")
class TCP_Android_Command_Server {
private var tcpserver: ServerSocket? = null
private var job: Job? = null
lateinit var tcpserver: ServerSocket
lateinit var job: Job
private val socketMap = mutableMapOf<String, Socket>()
lateinit var logcb: Consumer<String>
private val listUserLogin = mutableListOf<userLogin>()
@@ -46,13 +46,13 @@ class TCP_Android_Command_Server {
val tcp = ServerSocket(port)
tcpserver = tcp
job = CoroutineScope(Dispatchers.IO).launch {
Logger.info { "TCP server started" }
Logger.info { "TCP Android server started on port $port" }
while (isActive) {
if (tcpserver?.isClosed == true) break
if (tcpserver.isClosed) break
try {
tcpserver?.accept().use { socket ->
tcpserver.accept().use { socket ->
{
CoroutineScope(Dispatchers.Main).launch {
CoroutineScope(Dispatchers.IO).launch {
if (socket != null) {
// key is IP address only
val key: String = socket.inetAddress.hostAddress
@@ -416,20 +416,18 @@ class TCP_Android_Command_Server {
*/
fun StopTcpCommand(): Boolean {
try {
tcpserver?.close()
tcpserver.close()
runBlocking {
socketMap.values.forEach {
it.close()
}
socketMap.clear()
job?.join()
job.join()
}
Logger.info { "StopTcpCommand success" }
return true
} catch (e: Exception) {
Logger.error { "Failed to StopTcpServer, Message : ${e.message}" }
} finally {
tcpserver = null
}
return false
}

View File

@@ -14,8 +14,8 @@ import java.util.function.Consumer
@Suppress("unused")
class TCP_PC_Command_Server {
private var tcpserver: ServerSocket? = null
private var job: Job? = null
lateinit var tcpserver: ServerSocket
lateinit var job: Job
private val socketMap = mutableMapOf<String, Socket>()
/**
@@ -31,11 +31,11 @@ class TCP_PC_Command_Server {
job = CoroutineScope(Dispatchers.IO).launch {
Logger.info { "TCP server started" }
while (isActive) {
if (tcpserver?.isClosed == true) break
if (tcpserver.isClosed) break
try {
tcpserver?.accept().use { socket ->
tcpserver.accept().use { socket ->
{
CoroutineScope(Dispatchers.Main).launch {
CoroutineScope(Dispatchers.IO).launch {
if (socket != null) {
val key : String = socket.inetAddress.hostAddress+":"+socket.port
socketMap[key] = socket
@@ -81,20 +81,18 @@ class TCP_PC_Command_Server {
*/
fun StopTcpCommand(): Boolean {
try {
tcpserver?.close()
tcpserver.close()
runBlocking {
socketMap.values.forEach {
it.close()
}
socketMap.clear()
job?.join()
job.join()
}
Logger.info { "StopTcpCommand success" }
return true
} catch (e: Exception) {
Logger.error { "Failed to StopTcpServer, Message : ${e.message}" }
} finally {
tcpserver = null
}
return false
}

View File

@@ -20,4 +20,8 @@ data class Log(
return Log(0u, date, time, machine, description)
}
}
override fun toString() : String {
return "$datenya $timenya [$machine] $description"
}
}

View File

@@ -6,11 +6,13 @@ import content.Category
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import max_channel
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.tinylog.Logger
import java.sql.Connection
import java.sql.DriverManager
import java.util.function.Consumer
import kotlin.math.max
/**
* A class to manage a connection to a MariaDB database.
@@ -1464,7 +1466,7 @@ class MariaDB(
val countResult = statement?.executeQuery("SELECT COUNT(*) AS count FROM ${super.dbName}")
if (countResult?.next() == true) {
val count = countResult.getInt("count")
if (count == 0) {
if (count < max_channel) {
Logger.info("SoundChannel table is empty, populating with default channels" as Any)
Clear()
}
@@ -1578,9 +1580,9 @@ class MariaDB(
statement?.executeUpdate("TRUNCATE TABLE ${super.dbName}")
Logger.info("${super.dbName} table cleared" as Any)
List.clear()
// create new rows from 1 to 64 with description "Channel 01" to "Channel 64" and empty ip
for (i in 1..64) {
val channel = String.format("Channel %02d", i)
// create new rows from 1 to 64 with description "Channel 1" to "Channel 64" and empty ip
for (i in 1..max_channel) {
val channel = String.format("Channel %d", i)
val insertStatement =
connection.prepareStatement("INSERT INTO ${super.dbName} (channel, ip) VALUES (?, ?)")
insertStatement?.setString(1, channel)
@@ -1728,13 +1730,13 @@ class MariaDB(
statement?.setString(4, data.description)
val rowsAffected = statement?.executeUpdate()
if (rowsAffected != null && rowsAffected > 0) {
Logger.info("Log added: [$data.datenya $data.timenya] [$data.machine] $data.description" as Any)
Logger.info{"Log added : $data"}
return true
} else {
Logger.warn("No log entry added for: [$data.datenya $data.timenya] [$data.machine] $data.description" as Any)
Logger.warn{"Failed to add log entry : $data"}
}
} catch (e: Exception) {
Logger.error("Error adding log entry: ${e.message}" as Any)
Logger.error{"Error adding log entry: ${e.message}"}
}
return false
}

View File

@@ -1,4 +1,7 @@
package database
@Suppress("unused")
data class QueuePaging(var index: UInt, var Date_Time: String, var Source: String, var Type: String, var Message: String, var BroadcastZones: String)
data class QueuePaging(var index: UInt, var Date_Time: String, var Source: String, var Type: String, var Message: String, var BroadcastZones: String){
override fun toString(): String {
return "QueuePaging(index=$index, Date_Time='$Date_Time', Source='$Source', Type='$Type', Message='$Message', BroadcastZones='$BroadcastZones')"
}
}

View File

@@ -1,4 +1,8 @@
package database
@Suppress("unused")
data class QueueTable(var index: UInt, var Date_Time: String, var Source: String, var Type: String, var Message: String, var SB_TAGS: String, var BroadcastZones: String, var Repeat: UInt, var Language: String)
data class QueueTable(var index: UInt, var Date_Time: String, var Source: String, var Type: String, var Message: String, var SB_TAGS: String, var BroadcastZones: String, var Repeat: UInt, var Language: String){
override fun toString(): String {
return "QueueTable(index=$index, Date_Time='$Date_Time', Source='$Source', Type='$Type', Message='$Message', SB_TAGS='$SB_TAGS', BroadcastZones='$BroadcastZones', Repeat=$Repeat, Language='$Language')"
}
}