package barix 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.nio.ByteBuffer import java.util.function.Consumer @Suppress("unused") class TCP_Barix_Command_Server { lateinit var tcpserver: ServerSocket lateinit var job: Job private val socketMap = mutableMapOf() 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): 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()) while (isActive) { val length = ByteArray(4) din.readFully(length) val readlength = ByteBuffer.wrap(length).getInt() //println("Read Length : $readlength") val bb = ByteArray(readlength) din.readFully(bb) // B4A format, 4 bytes di depan adalah size val str = String(bb) //println("Received from $key : $str") if (ValidString(str)) { // Valid command from Barix is in format $"STATUSBARIX;VU;BuffRemain;StatusData"$ pattern.find(str)?.let { matchResult -> val (vu, buffremain, statusdata) = matchResult.destructured val status = BarixStatus( socket.inetAddress.hostAddress, vu.toInt(), buffremain.toInt(), statusdata.toIntOrNull() ?: 0 ) //Logger.info { "Received valid command from $key : $status" } cb.accept(status) } ?: run { Logger.warn { "Invalid command format from $key : $str" } } } } } catch (ex:Exception){ 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] } }