Commit 29/09/2025
This commit is contained in:
@@ -10,6 +10,8 @@ import kotlinx.coroutines.runBlocking
|
||||
import org.tinylog.Logger
|
||||
import java.net.ServerSocket
|
||||
import java.net.Socket
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.util.function.Consumer
|
||||
|
||||
@Suppress("unused")
|
||||
@@ -17,14 +19,16 @@ class TCP_Android_Command_Server {
|
||||
private var tcpserver: ServerSocket? = null
|
||||
private var job: Job? = null
|
||||
private val socketMap = mutableMapOf<String, Socket>()
|
||||
lateinit var logcb: Consumer<String>
|
||||
|
||||
/**
|
||||
* Start TCP Command Server
|
||||
* @param port The port to listen on, default is 5003
|
||||
* @param cb The callback function to handle incoming messages
|
||||
* @param logCB Callback to handle Log messages
|
||||
* @return true if successful
|
||||
*/
|
||||
fun StartTcpServer(port: Int = 5003, cb: Consumer<String>): Boolean {
|
||||
fun StartTcpServer(port: Int = 5003, logCB: Consumer<String>): Boolean {
|
||||
logcb = logCB
|
||||
try {
|
||||
val tcp = ServerSocket(port)
|
||||
tcpserver = tcp
|
||||
@@ -37,27 +41,32 @@ class TCP_Android_Command_Server {
|
||||
{
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
if (socket != null) {
|
||||
val key : String = socket.inetAddress.hostAddress+":"+socket.port
|
||||
val key: String = socket.inetAddress.hostAddress + ":" + socket.port
|
||||
socketMap[key] = socket
|
||||
Logger.info { "Start communicating with $key" }
|
||||
socket.getInputStream().use { din ->
|
||||
socket.getInputStream().let { din ->
|
||||
{
|
||||
while (isActive) {
|
||||
if (din.available()>0){
|
||||
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)
|
||||
val str = String(bb, 4, bb.size - 4)
|
||||
str.split("@").map { it.trim() }.filter { ValidString(it) }
|
||||
.map { it.uppercase() }.forEach {
|
||||
process_command(it) { reply ->
|
||||
try {
|
||||
socket.getOutputStream().write(String_to_Byte_Android(reply))
|
||||
} catch (e: Exception) {
|
||||
logcb.accept("Failed to send reply to $key, Message : ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.info { "Finished communicating with $key" }
|
||||
logcb.accept("Finished communicatiing with $key")
|
||||
socketMap.remove(key)
|
||||
}
|
||||
|
||||
@@ -66,19 +75,84 @@ class TCP_Android_Command_Server {
|
||||
}
|
||||
|
||||
} catch (ex: Exception) {
|
||||
Logger.error { "Failed accepting TCP Socket, Message : ${ex.message}" }
|
||||
logcb.accept("Failed accepting TCP Socket, Message : ${ex.message}")
|
||||
}
|
||||
|
||||
}
|
||||
Logger.info { "TCP server stopped" }
|
||||
logcb.accept("TCP server stopped")
|
||||
}
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
Logger.error { "Failed to StartTcpServer, Message : ${e.message}" }
|
||||
logcb.accept("Failed to StartTcpServer, Message : ${e.message}")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a String to ByteArray in prefix AsyncStream format in B4X
|
||||
* @param str The input string
|
||||
* @return ByteArray with 4 bytes prefix length + string bytes
|
||||
*/
|
||||
private fun String_to_Byte_Android(str: String): ByteArray {
|
||||
if (ValidString(str)) {
|
||||
val len = str.length
|
||||
val bytes = str.toByteArray()
|
||||
return ByteBuffer.allocate(len + 4)
|
||||
.order(ByteOrder.LITTLE_ENDIAN)
|
||||
.putInt(len)
|
||||
.put(bytes)
|
||||
.array()
|
||||
}
|
||||
return ByteArray(0)
|
||||
}
|
||||
|
||||
private fun process_command(cmd: String, cb: Consumer<String>) {
|
||||
Logger.info { "Command from Android: $cmd" }
|
||||
val parts = cmd.split(";").map { it.trim() }.filter { it.isNotBlank() }.map { it.uppercase() }
|
||||
when (parts[0]) {
|
||||
"GETLOGIN" -> {
|
||||
val username = parts.getOrElse(1) { "" }
|
||||
val password = parts.getOrElse(2) { "" }
|
||||
if (ValidString(username) && ValidString(password)) {
|
||||
//TODO handle login here
|
||||
} else cb.accept("LOGIN;FALSE@")
|
||||
}
|
||||
|
||||
"PCMFILE_START" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"PCMFILE_STOP" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"STARTPAGINGAND" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"STOPPAGINGAND" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"CANCELPAGINGAND" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"STARTINITIALIZE" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
"BROADCASTAND" -> {
|
||||
// TODO read coding here
|
||||
}
|
||||
|
||||
else -> {
|
||||
logcb.accept("Unknown command from Android: $cmd")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop TCP Command Server
|
||||
* @return true if succesful
|
||||
|
||||
Reference in New Issue
Block a user