172 lines
7.8 KiB
Kotlin
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]
|
|
}
|
|
|
|
|
|
} |