690 lines
34 KiB
Kotlin
690 lines
34 KiB
Kotlin
package commandServer
|
|
|
|
import audioPlayer
|
|
import codes.Somecodes.Companion.ValidString
|
|
import codes.Somecodes.Companion.datetimeformat1
|
|
import content.Category
|
|
import content.Language
|
|
import database.Messagebank
|
|
import database.QueuePaging
|
|
import database.QueueTable
|
|
import database.Soundbank
|
|
import db
|
|
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 tcpreceiver
|
|
import udpreceiver
|
|
import java.net.ServerSocket
|
|
import java.net.Socket
|
|
import java.nio.ByteBuffer
|
|
import java.nio.ByteOrder
|
|
import java.time.LocalDateTime
|
|
import java.util.function.Consumer
|
|
import kotlin.io.path.absolutePathString
|
|
|
|
@Suppress("unused")
|
|
class TCP_Android_Command_Server {
|
|
lateinit var tcpserver: ServerSocket
|
|
lateinit var job: Job
|
|
private val socketMap = mutableMapOf<String, Socket>()
|
|
lateinit var logcb: Consumer<String>
|
|
private val listUserLogin = mutableListOf<userLogin>()
|
|
private val listOnGoingPaging = mutableMapOf<String, PagingJob>()
|
|
|
|
/**
|
|
* Start TCP Command Server
|
|
* @param port The port to listen on, default is 5003
|
|
* @param logCB Callback to handle Log messages
|
|
* @return true if successful
|
|
*/
|
|
fun StartTcpServer(port: Int = 5003, logCB: Consumer<String>): Boolean {
|
|
logcb = logCB
|
|
try {
|
|
val tcp = ServerSocket(port)
|
|
tcpserver = tcp
|
|
job = CoroutineScope(Dispatchers.IO).launch {
|
|
Logger.info { "TCP Android server started on port $port" }
|
|
while (isActive) {
|
|
if (tcpserver.isClosed) break
|
|
try {
|
|
val socket = tcpserver.accept()
|
|
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
if (socket != null) {
|
|
// key is IP address only
|
|
val key: String = socket.inetAddress.hostAddress
|
|
socketMap[key] = socket
|
|
Logger.info { "Start communicating with IPMT/IPM with IP $key" }
|
|
val din = socket.getInputStream()
|
|
val dout = socket.getOutputStream()
|
|
try{
|
|
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)
|
|
//println("Received command from $key : $str")
|
|
str.split("@").map { it.trim() }.filter { ValidString(it) }
|
|
.forEach {
|
|
process_command(key,it) { reply ->
|
|
try {
|
|
val cc = String_to_Byte_Android(reply)
|
|
if (cc.isNotEmpty()){
|
|
dout.write(cc)
|
|
dout.flush()
|
|
//Logger.info{"Sent reply ${cc.size} bytes to $key : $reply"}
|
|
} else Logger.error { "Empty reply to send to $key" }
|
|
|
|
} catch (e: Exception) {
|
|
logcb.accept("Send reply to $key failed, reply=$reply, Message : $e")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (e : Exception){
|
|
logcb.accept("Exception in communication with $key, Message : ${e.message}")
|
|
}
|
|
|
|
logcb.accept("Finished communicatiing with $key")
|
|
CloseSocket(socket)
|
|
socketMap.remove(key)
|
|
}
|
|
|
|
}
|
|
|
|
} catch (ex: Exception) {
|
|
logcb.accept("Android TCP Server Failed accepting TCP Socket, Message : ${ex.message}")
|
|
}
|
|
|
|
}
|
|
logcb.accept("Android TCP Command server stopped")
|
|
}
|
|
return true
|
|
} catch (e: Exception) {
|
|
logcb.accept("Failed to StartTcpServer, Message : ${e.message}")
|
|
}
|
|
return false
|
|
}
|
|
|
|
private fun CloseSocket(socket : Socket) {
|
|
try {
|
|
socket.close()
|
|
} catch (e: Exception) {
|
|
Logger.error { "Failed to close socket, Message : ${e.message}" }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 bytes = str.toByteArray()
|
|
val len = str.length
|
|
|
|
return ByteBuffer.allocate(len + 4)
|
|
.order(ByteOrder.LITTLE_ENDIAN)
|
|
.putInt(0,len)
|
|
.put(4,bytes)
|
|
.array()
|
|
}
|
|
return ByteArray(0)
|
|
}
|
|
|
|
/**
|
|
* Process command from Android client
|
|
* @param key The client IP address
|
|
* @param cmd The command string
|
|
* @param cb Callback to send reply string
|
|
*/
|
|
private fun process_command(key: String, cmd: String, cb: Consumer<String>) {
|
|
if ("PING" != cmd) Logger.info { "Command from $key : $cmd" }
|
|
val parts = cmd.split(";").map { it.trim() }.filter { it.isNotBlank() }
|
|
when (parts[0]) {
|
|
"GETLOGIN" -> {
|
|
// Android login request
|
|
val username = parts.getOrElse(1) { "" }
|
|
val password = parts.getOrElse(2) { "" }
|
|
if (ValidString(username) && ValidString(password)) {
|
|
if (db.userDB.List.any{
|
|
it.username==username && it.password==password}) {
|
|
val existing = listUserLogin.find { it.ip == key}
|
|
if (existing!=null){
|
|
existing.username = username
|
|
} else{
|
|
listUserLogin.add(userLogin(key, username))
|
|
}
|
|
cb.accept("LOGIN;TRUE@")
|
|
logcb.accept("Android Login success from $key as $username")
|
|
return
|
|
} else {
|
|
logcb.accept("Android Login failed from $key as $username")
|
|
cb.accept("LOGIN;FALSE@")
|
|
}
|
|
} else {
|
|
logcb.accept("Android Login failed from $key with empty username or password")
|
|
cb.accept("LOGIN;FALSE@")
|
|
}
|
|
}
|
|
|
|
"PING" -> {
|
|
// simple ping command
|
|
cb.accept("PONG@")
|
|
}
|
|
|
|
"PCMFILE_START" ->{
|
|
// start sending PCM data from Android for paging
|
|
val size = parts.getOrElse(1) { "0" }.toInt()
|
|
val filename = parts.getOrElse(2) { "" }
|
|
val zones = parts.getOrElse(3) { "" }.replace(",",";")
|
|
if (size>0){
|
|
if (ValidString(filename)){
|
|
if (ValidString(zones)){
|
|
// create paging job
|
|
val pj = PagingJob(key, zones)
|
|
// ada expected size
|
|
pj.expectedSize = size
|
|
// masukin ke list
|
|
listOnGoingPaging[key] = pj
|
|
Logger.info{"PagingJob created for Android $key, zones: $zones, file: ${pj.filePath.absolutePathString()}"}
|
|
|
|
tcpreceiver.RequestDataFrom(key) {
|
|
// push data ke paging job
|
|
pj.addData(it, it.size)
|
|
}
|
|
cb.accept("PCMFILE_START;OK@")
|
|
Logger.info{"Android $key start sending PCM data, expecting $size bytes"}
|
|
return
|
|
|
|
} else logcb.accept("PCMFILE_START from Android $key failed, empty zones")
|
|
} else logcb.accept("PCMFILE_START from Android $key failed, empty filename")
|
|
} else logcb.accept("PCMFILE_START from Android $key failed, invalid size")
|
|
cb.accept("PCMFILE_START;NG@")
|
|
}
|
|
"PCMFILE_STOP" -> {
|
|
// stop sending PCM data from Android for paging
|
|
val pj = listOnGoingPaging[key]
|
|
if (pj!=null) {
|
|
listOnGoingPaging.remove(key)
|
|
tcpreceiver.StopRequestDataFrom(key)
|
|
// get remaining data
|
|
val data = pj.GetData()
|
|
pj.Close()
|
|
if (data.size==pj.expectedSize){
|
|
Logger.info { "Paging job closed from Android $key, total bytes received ${data.size}, writing to file ${pj.filePath.absolutePathString()}" }
|
|
val result = audioPlayer.WavWriter(data, pj.filePath.absolutePathString(), true)
|
|
if (result.success) {
|
|
Logger.info{"Paging audio file written from Android $key to ${pj.filePath.absolutePathString()}"}
|
|
val qp = QueuePaging(
|
|
0u,
|
|
LocalDateTime.now().format(datetimeformat1),
|
|
"ANDROID",
|
|
"PAGING",
|
|
pj.filePath.absolutePathString(),
|
|
pj.broadcastzones
|
|
)
|
|
Logger.info{"Inserting paging audio to queue paging table from Android $key, data=$qp"}
|
|
if (db.queuepagingDB.Add(qp)) {
|
|
db.queuepagingDB.Resort()
|
|
logcb.accept("Paging audio inserted to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
|
|
cb.accept("PCMFILE_STOP;OK@")
|
|
return
|
|
} else logcb.accept("Failed to insert paging audio to queue paging table from Android $key, file ${pj.filePath.absolutePathString()}")
|
|
} else logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : ${result.message}")
|
|
} else logcb.accept("PCMFILE_STOP from Android $key received size ${data.size} does not match expected ${pj.expectedSize}")
|
|
} else logcb.accept("PCMFILE_STOP from Android $key failed, no ongoing PCM data receiving")
|
|
cb.accept("PCMFILE_STOP;NG@")
|
|
}
|
|
|
|
"STARTPAGINGAND" -> {
|
|
// Start Paging request from IPM
|
|
val zones = parts.getOrElse(1) { "" }.replace(",",";")
|
|
if (ValidString(zones)){
|
|
// create pagingjob
|
|
val pj = PagingJob(key, zones)
|
|
// masukin ke list
|
|
listOnGoingPaging[key] = pj
|
|
Logger.info{"PagingJob created for IPM $key, zones: $zones, file: ${pj.filePath.absolutePathString()}"}
|
|
|
|
// start minta data dari udpreceiver
|
|
udpreceiver.RequestDataFrom(key){
|
|
// push data ke paging job
|
|
pj.addData(it, it.size)
|
|
}
|
|
logcb.accept("Paging started from IPM $key")
|
|
cb.accept("STARTPAGINGAND;OK@")
|
|
return
|
|
} else logcb.accept("Paging start from IPM $key failed, empty zones")
|
|
cb.accept("STARTPAGINGAND;NG@")
|
|
}
|
|
|
|
"STOPPAGINGAND" -> {
|
|
// stop paging request from IPM
|
|
val pj = listOnGoingPaging[key]
|
|
if (pj!=null){
|
|
listOnGoingPaging.remove(key)
|
|
udpreceiver.StopRequestDataFrom(key)
|
|
logcb.accept("Paging stopped from IPM $key")
|
|
// get remaining data
|
|
val data = pj.GetData()
|
|
pj.Close()
|
|
Logger.info{"Paging job closed from IPM $key, total bytes received ${data.size}, writing to file ${pj.filePath.absolutePathString()}"}
|
|
val result = audioPlayer.WavWriter(data, pj.filePath.absolutePathString(), true)
|
|
if (result.success){
|
|
val qp = QueuePaging(
|
|
0u,
|
|
LocalDateTime.now().format(datetimeformat1),
|
|
"IPM",
|
|
"PAGING",
|
|
pj.filePath.absolutePathString(),
|
|
pj.broadcastzones
|
|
)
|
|
if (db.queuepagingDB.Add(qp)){
|
|
db.queuepagingDB.Resort()
|
|
logcb.accept("Paging audio inserted to queue paging table from IPM $key, file ${pj.filePath.absolutePathString()}")
|
|
cb.accept("STOPPAGINGAND;OK@")
|
|
return
|
|
} else logcb.accept("Failed to insert paging audio to queue paging table from IPM $key, file ${pj.filePath.absolutePathString()}")
|
|
} else logcb.accept("Failed to write paging audio to file ${pj.filePath.absolutePathString()}, Message : ${result.message}")
|
|
} else logcb.accept("Paging stop from IPM $key failed, no ongoing paging")
|
|
cb.accept("STOPPAGINGAND;NG@")
|
|
|
|
}
|
|
|
|
"CANCELPAGINGAND" -> {
|
|
// cancel paging request from IPM
|
|
val pj = listOnGoingPaging[key]
|
|
if (pj!=null){
|
|
pj.Close()
|
|
listOnGoingPaging.remove(key)
|
|
udpreceiver.StopRequestDataFrom(key)
|
|
logcb.accept("Paging from IPM $key cancelled")
|
|
cb.accept("CANCELPAGINGAND;OK@")
|
|
return
|
|
} else logcb.accept("Paging cancel from IPM $key failed, no ongoing paging")
|
|
cb.accept("CANCELPAGINGAND;NG@")
|
|
|
|
}
|
|
|
|
"STARTINITIALIZE" -> {
|
|
val username = parts.getOrElse(1) { "" }
|
|
if (ValidString(username)){
|
|
val userlogin = listUserLogin.find { it.username == username }
|
|
if (userlogin != null){
|
|
val userdb = db.userDB.List.find { it.username == username }
|
|
if (userdb != null){
|
|
//println("Sending initialization data to $key with username $username")
|
|
val result = StringBuilder()
|
|
// kirim Zone
|
|
result.append("ZONE")
|
|
userdb.broadcastzones.split(";").map { it.trim() }.filter { it.isNotBlank() }.forEach {
|
|
result.append(";")
|
|
result.append(it)
|
|
}
|
|
result.append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim MSGTOTAL
|
|
result.clear()
|
|
val VARMESSAGES = mutableListOf<Messagebank>()
|
|
result.append("MSGTOTAL;")
|
|
userdb.messagebank_ann_id
|
|
// messagebank_ann_id adalah rentengan ANN_ID (digit) yang dipisah dengan ;
|
|
.split(";")
|
|
// trim dulu
|
|
.map { it.trim() }
|
|
// bukan string kosong antar dua tanda ;
|
|
.filter { it.isNotBlank() }
|
|
// iterasi setiap ANN_ID
|
|
.forEach { annid ->
|
|
// masukin ke VARMESSAGES yang unik secara ANN_ID dan Language
|
|
val xx = db.messageDB.List
|
|
.asSequence()
|
|
.filter{it.ANN_ID == annid.toUInt()}
|
|
.distinctBy { it.ANN_ID }
|
|
|
|
VARMESSAGES.addAll(xx)
|
|
}
|
|
result.append(VARMESSAGES.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARAPTOTAL
|
|
result.clear()
|
|
result.append("VARAPTOTAL;")
|
|
val VARAPTOTAL = mutableListOf<Soundbank>()
|
|
userdb.airline_tags
|
|
.split(";")
|
|
.map { it.trim() }
|
|
.filter { it.isNotBlank() }
|
|
.forEach { al ->
|
|
val sb = db.soundDB.List
|
|
.filter { it.Category.equals(Category.Airplane_Name.name, true) }
|
|
.filter { it.TAG.equals(al, true)}
|
|
.distinctBy { it.TAG }
|
|
VARAPTOTAL.addAll(sb)
|
|
}
|
|
result.append(VARAPTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARCITYTOTAL
|
|
result.clear()
|
|
result.append("VARCITYTOTAL;")
|
|
val VARCITYTOTAL = mutableListOf<Soundbank>()
|
|
userdb.city_tags
|
|
.split(";")
|
|
.map { it.trim() }
|
|
.filter { it.isNotBlank() }
|
|
.forEach { ct ->
|
|
val sb = db.soundDB.List
|
|
.filter { it.Category.equals(Category.City.name, true) }
|
|
.filter { it.TAG.equals(ct, true)}
|
|
.distinctBy { it.TAG }
|
|
VARCITYTOTAL.addAll(sb)
|
|
}
|
|
result.append(VARCITYTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARPLACESTOTAL
|
|
result.clear()
|
|
result.append("VARPLACESTOTAL;")
|
|
val VARPLACESTOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Places.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARPLACESTOTAL.add(it)
|
|
}
|
|
result.append(VARPLACESTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARSHALATTOTAL
|
|
result.clear()
|
|
result.append("VARSHALATTOTAL;")
|
|
val VARSHALATTOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Shalat.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARSHALATTOTAL.add(it)
|
|
}
|
|
result.append(VARSHALATTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARSEQUENCETOTAL
|
|
result.clear()
|
|
result.append("VARSEQUENCETOTAL;")
|
|
val VARSEQUENCETOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Sequence.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARSEQUENCETOTAL.add(it)
|
|
}
|
|
result.append(VARSEQUENCETOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARREASONTOTAL
|
|
result.clear()
|
|
result.append("VARREASONTOTAL;")
|
|
val VARREASONTOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Reason.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARREASONTOTAL.add(it)
|
|
}
|
|
result.append(VARREASONTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARPROCEDURETOTAL
|
|
val VARPROCEDURETOTAL = mutableListOf<Soundbank>()
|
|
result.clear()
|
|
result.append("VARPROCEDURETOTAL;")
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Procedure.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARPROCEDURETOTAL.add(it)
|
|
}
|
|
result.append(VARPROCEDURETOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARGATETOTAL
|
|
val VARGATETOTAL = mutableListOf<Soundbank>()
|
|
result.clear()
|
|
result.append("VARGATETOTAL;")
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Gate.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARGATETOTAL.add(it)
|
|
}
|
|
result.append(VARGATETOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARCOMPENSATIONTOTAL
|
|
result.clear()
|
|
result.append("VARCOMPENSATIONTOTAL;")
|
|
val VARCOMPENSATIONTOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Compensation.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARCOMPENSATIONTOTAL.add(it)
|
|
}
|
|
result.append(VARCOMPENSATIONTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
// kirim VARGREETINGTOTAL
|
|
result.clear()
|
|
result.append("VARGREETINGTOTAL;")
|
|
val VARGREETINGTOTAL = mutableListOf<Soundbank>()
|
|
db.soundDB.List
|
|
.filter { it.Category.equals(Category.Greeting.name, true) }
|
|
.distinctBy { it.TAG }
|
|
.forEach {
|
|
VARGREETINGTOTAL.add(it)
|
|
}
|
|
result.append(VARGREETINGTOTAL.size).append("@")
|
|
cb.accept(result.toString())
|
|
|
|
//Append MSG, for Android only Indonesia and English
|
|
if (VARMESSAGES.isNotEmpty()) {
|
|
result.clear()
|
|
VARMESSAGES.forEachIndexed { index, msg ->
|
|
|
|
val ann_id = msg.ANN_ID
|
|
val msg_indo = db.messageDB.List.find {
|
|
it.ANN_ID == ann_id && it.Language.equals(
|
|
Language.INDONESIA.name,
|
|
true
|
|
)
|
|
}
|
|
val msg_eng = db.messageDB.List.find {
|
|
it.ANN_ID == ann_id && it.Language.equals(
|
|
Language.ENGLISH.name,
|
|
true
|
|
)
|
|
}
|
|
val description = msg_indo?.Description ?: msg_eng?.Description ?: "UNKNOWN"
|
|
result.append("MSG;$index;$ann_id;$description;")
|
|
result.append(msg_indo?.Message_Detail ?:"").append(";")
|
|
result.append(msg_eng?.Message_Detail ?:"").append("@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARAP
|
|
if (VARAPTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARAPTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARAP;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARCITY
|
|
if (VARCITYTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARCITYTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARCITY;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARPLACES
|
|
if (VARPLACESTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARPLACESTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARPLACES;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
// append VARSHALAT
|
|
if (VARSHALATTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARSHALATTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARSHALAT;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARSEQUENCE
|
|
if (VARSEQUENCETOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARSEQUENCETOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARSEQUENCE;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARREASON
|
|
if (VARREASONTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARREASONTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARREASON;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARPROCEDURE
|
|
if (VARPROCEDURETOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARPROCEDURETOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARPROCEDURE;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARGATE
|
|
if (VARGATETOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARGATETOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARGATE;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARCOMPENSATION
|
|
if (VARCOMPENSATIONTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARCOMPENSATIONTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARCOMPENSATION;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
// append VARGREETING
|
|
if (VARGREETINGTOTAL.isNotEmpty()) {
|
|
result.clear()
|
|
VARGREETINGTOTAL.forEachIndexed { index, sb ->
|
|
result.append("VARGREETING;$index;${sb.TAG};${sb.Description}@")
|
|
}
|
|
cb.accept(result.toString())
|
|
}
|
|
|
|
logcb.accept("All variables sent to $key with username $username")
|
|
return
|
|
} else logcb.accept("STARTINITIALIZE failed from $key with username $username not found in userDB")
|
|
} else logcb.accept("STARTINITIALIZE failed from $key with unregistered username $username")
|
|
} else logcb.accept("STARTINITIALIZE failed from $key with empty username")
|
|
cb.accept("STARTINITIALIZE;FALSE@")
|
|
}
|
|
|
|
"BROADCASTAND" -> {
|
|
// semi auto dari android, masukin ke queue table
|
|
val desc = parts.getOrElse(1) { "" }
|
|
// language bisa lebih dari satu, dipisah dengan koma
|
|
val lang = parts.getOrElse(2) { "" }.replace(",",";")
|
|
// tags bisa lebih dari satu, dipisah dengan spasi
|
|
val tags = parts.getOrElse(3) { "" }.replace(",",";")
|
|
// zone bisa lebih dari satu, dipisah dengan koma
|
|
val zone = parts.getOrElse(4) { "" }.replace(",",";")
|
|
if (ValidString(desc)){
|
|
if (ValidString(lang)){
|
|
if (ValidString(tags)){
|
|
if (ValidString(zone)){
|
|
val qt = QueueTable(
|
|
0u,
|
|
LocalDateTime.now().format(datetimeformat1),
|
|
"ANDROID",
|
|
"SOUNDBANK",
|
|
desc,
|
|
tags,
|
|
zone,
|
|
1u,
|
|
lang
|
|
)
|
|
if (db.queuetableDB.Add(qt)){
|
|
db.queuetableDB.Resort()
|
|
logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} inserted. Message: $desc;$lang;$tags;$zone")
|
|
cb.accept("BROADCASTAND;OK@")
|
|
return
|
|
} else logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} failed, cannot add to queue table")
|
|
} else logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} failed, empty zone")
|
|
} else logcb.accept("Broadcsast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} failed, empty tags")
|
|
} else logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} failed, empty language")
|
|
} else logcb.accept("Broadcast request from Android $key username=${listUserLogin.find { it.ip==key }?.username ?: "UNKNOWN"} failed, empty description")
|
|
cb.accept("BROADCASTAND;NG@")
|
|
|
|
}
|
|
|
|
else -> {
|
|
logcb.accept("Unknown command from Android: $cmd")
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
}
|
|
} |