Files
AAS_NewGeneration/src/commandServer/TCP_Android_Command_Server.kt
2025-09-03 16:01:18 +07:00

105 lines
4.1 KiB
Kotlin

package commandServer
import codes.Somecodes.Companion.ValidString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.tinylog.Logger
import java.net.ServerSocket
import java.net.Socket
import java.util.function.Consumer
@Suppress("unused")
class TCP_Android_Command_Server {
private var tcpserver: ServerSocket? = null
private var job: Job? = null
private val socketMap = mutableMapOf<String, Socket>()
/**
* Start TCP Command Server
* @param port The port to listen on, default is 5003
* @param cb The callback function to handle incoming messages
* @return true if successful
*/
fun StartTcpServer(port: Int = 5003, cb: Consumer<String>): Boolean {
try {
val tcp = ServerSocket(port)
tcpserver = tcp
job = CoroutineScope(Dispatchers.IO).launch {
Logger.info { "TCP server started" }
while (isActive) {
if (tcpserver?.isClosed == true) break
try {
tcpserver?.accept().use { socket ->
{
CoroutineScope(Dispatchers.Main).launch {
if (socket != null) {
val key : String = socket.inetAddress.hostAddress+":"+socket.port
socketMap[key] = socket
Logger.info { "Start communicating with $key" }
socket.getInputStream().use { din ->
{
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)
str.split("@").forEach {
if (ValidString(it)){
cb.accept(it)
}
}
}
}
}
}
Logger.info { "Finished communicating with $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}" }
} finally {
tcpserver = null
}
return false
}
}