Files
AAS_NewGeneration/src/barix/TCP_Barix_Command_Server.kt
2026-02-12 17:08:20 +07:00

172 lines
7.8 KiB
Kotlin

package barix
import codes.Somecodes.Companion.LitteEndianToInt
import codes.Somecodes.Companion.ValidString
import kotlinx.coroutines.*
import org.tinylog.Logger
import java.io.DataInputStream
import java.net.ServerSocket
import java.net.Socket
import java.util.function.Consumer
class TCP_Barix_Command_Server {
lateinit var tcpserver: ServerSocket
lateinit var job: Job
private val socketMap = mutableMapOf<String, Socket>()
//private val regex = """STATUSBARIX;(\d+);(\d+)(;(\d+))?"""
//private val pattern = Regex(regex)
/**
* Start TCP Command Server
* @param port The port number to listen on (default is 5001)
* @param cb A callback function that will be called when a valid command is received
* @return true if successful
*/
fun StartTcpServer(port: Int = 5001, cb: Consumer<BarixStatus>): Boolean {
try {
val tcp = ServerSocket(port)
tcpserver = tcp
job = CoroutineScope(Dispatchers.IO).launch {
Logger.info { "TCP StreamerOutput server started on port $port" }
while (isActive) {
if (tcpserver.isClosed) break
try {
val socket = tcpserver.accept()
CoroutineScope(Dispatchers.IO).launch {
val key : String = socket.inetAddress.hostAddress
socketMap[key] = socket
Logger.info { "Start communicating with Streamer Output with IP : $key" }
try{
val din = DataInputStream(socket.getInputStream())
var VuZeroCounter = 0L
while (isActive) {
val bb = ByteArray(128)
val readbytes = din.read(bb)
if (readbytes == -1) {
Logger.info { "Connection closed by Streamer Output with IP $key" }
break
}
if (readbytes == 0) continue
var stringlength = 0
try{
stringlength = LitteEndianToInt(bb[0], bb[1], bb[2], bb[3])
if (stringlength<1 || stringlength>bb.size-4) throw Exception("Invalid string length $stringlength")
} catch (ex:Exception){
Logger.error { "Error reading length from Streamer Output with IP $key, Message : ${ex.message}" }
continue
}
var str = String(bb,4, stringlength).trim()
if (str.isBlank()) continue
if (!str.startsWith("STATUSBARIX")) continue
if (str.endsWith("@")) str = str.removeSuffix("@")
if (ValidString(str)) {
// Valid command from StreamerOutput is in format $"STATUSBARIX;VU;BuffRemain;StatusData"$
// Valid command from Barix is in format $"STATUSBARIX;VU;BuffRemain"$
val values = str.split(";")
if (values.size<3) continue
if ("STATUSBARIX" != values[0]) continue
val vu = values[1].toIntOrNull() ?: continue
val buffremain = values[2].toIntOrNull() ?: continue
var status: BarixStatus
when(values.size){
3 ->{
// mode barix
// kadang vu stuck tidak di 0 saat idle,
// jadi kalau vu <512 selama 10 kali berturut2
// dan buffer lebih dari 16000, anggap idle
if ((vu < 512) && (buffremain>=16000)){
VuZeroCounter++
} else {
VuZeroCounter = 0
}
// statusdata = isplaying = , if VuZeroCounter >=10 then idle (0) else playing (1)
val statusdata = if (VuZeroCounter>=10) 0 else 1
status = BarixStatus(
socket.inetAddress.hostAddress,
vu,
buffremain,
statusdata,
true
)
}
4 ->{
// mode Q-AG1
val statusdata = values[3].toIntOrNull() ?: 0
status = BarixStatus(
socket.inetAddress.hostAddress,
vu,
buffremain,
statusdata,
false
)
}
else -> continue
}
cb.accept(status)
}
}
} catch (ex:Exception){
if (ex.message!=null) Logger.error { "Error in communication with Streamer Output with IP $key, Message : ${ex.message}" }
}
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}" }
}
}
Logger.info { "TCP server stopped" }
}
return true
} catch (e: Exception) {
Logger.error { "Failed to StartTcpServer, Message : ${e.message}" }
}
return false
}
/**
* Stop TCP Command Server
* @return true if succesful
*/
fun StopTcpCommand(): Boolean {
try {
tcpserver.close()
runBlocking {
socketMap.values.forEach {
it.close()
}
socketMap.clear()
job.join()
}
Logger.info { "StopTcpCommand success" }
return true
} catch (e: Exception) {
Logger.error { "Failed to StopTcpServer, Message : ${e.message}" }
}
return false
}
/**
* Get Socket by IP address
* @param ip The IP address of the client
* @return Socket if found, null otherwise
*/
fun getSocket(ip: String): Socket? {
return socketMap[ip]
}
}