Explorar o código

fix byte chunk function

herlanS_ %!s(int64=3) %!d(string=hai) anos
pai
achega
761db8c5ad

+ 43 - 141
src/main/kotlin/co/id/datacomsolusindo/ipphonebridge/BridgeFIlter.kt

@@ -1,9 +1,7 @@
 package co.id.datacomsolusindo.ipphonebridge
 
-import com.fasterxml.jackson.core.type.TypeReference
 import com.fasterxml.jackson.databind.ObjectMapper
 import com.fasterxml.jackson.databind.ObjectWriter
-import org.apache.commons.io.IOUtils
 import org.apache.logging.log4j.LogManager
 import org.springframework.context.annotation.Configuration
 import org.springframework.core.Ordered
@@ -12,16 +10,8 @@ import org.springframework.core.io.ResourceLoader
 import org.springframework.http.HttpHeaders
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpStatus
-import org.springframework.messaging.handler.annotation.DestinationVariable
-import org.springframework.messaging.handler.annotation.MessageMapping
-import org.springframework.messaging.handler.annotation.SendTo
 import org.springframework.messaging.simp.SimpMessagingTemplate
 import org.springframework.stereotype.Component
-import org.springframework.stereotype.Controller
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.PathVariable
-import org.springframework.web.bind.annotation.PostMapping
-import org.springframework.web.bind.annotation.RestController
 import org.springframework.web.servlet.config.annotation.EnableWebMvc
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@@ -33,6 +23,9 @@ import java.net.InetAddress
 import java.time.Duration
 import java.time.LocalDateTime
 import java.util.*
+import java.util.Collections.synchronizedList
+import java.util.concurrent.ConcurrentHashMap
+import java.util.concurrent.ConcurrentMap
 import java.util.concurrent.TimeUnit
 import javax.servlet.*
 import javax.servlet.http.HttpServletRequest
@@ -88,6 +81,10 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
             if (search != null && !search.endsWith("assets/bootstrap.js")) {
                 res.sendRedirect("/resources/$search")
             } else {
+
+                LogManager.getLogger("client-$client")
+                    .info("Request Start, UA: " + req.getHeader("User-Agent") + " From: " + InetAddress.getLocalHost().hostAddress + " To: " + req.requestURL.toString() + "?" + req.queryString)
+
 //                if (req.getHeader("User-Agent").contains("(dart:io)") || req.requestURL.toString().endsWith("api/license")) {
                 val reqId = UUID.randomUUID().toString()
                 try {
@@ -112,29 +109,13 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                         rb.body = body
                     }
 
-                    Singletons.requestInstance[reqId] = RequestQue(reqId, rb, null)
+                    Singletons.requestInstance.getOrPut(reqId){ RequestQue(reqId, rb, null)}
                     val ow: ObjectWriter = ObjectMapper().writer().withDefaultPrettyPrinter()
                     val partStr = ow.writeValueAsString(rb).chunked(1500)
-
-
-//                    val mid = UUID.randomUUID().toString()
-//                    partStr.forEachIndexed(
-//
-//                    )
-//                    val mList = mutableListOf<Message>()
-//                    partStr.forEachIndexed { i, s ->
-//                        mList.add(Message(mid, s, i + 1, partStr.size))
-//                    }
-//                    Singletons.sendQueue[mid] = mList.sortedBy { it.part }.toMutableList()
-                    //send first
-                    //template.convertAndSend("/topic/request/$client",Singletons.sendQueue[mid]!!.first())
-
-
-//                    LogManager.getLogger(this.javaClass).info("part size ${partStr.size}")
-//                    if (partStr.size > 1) {
                     val partialID = UUID.randomUUID().toString()
                     val st2 = System.nanoTime()
 
+//                    println("req id $reqId")
                     partStr.forEachIndexed { idx, it ->
                         template.convertAndSend(
                             "/topic/partial/$client",
@@ -144,7 +125,8 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
 
 
                     var i = 0
-                    while (Singletons.responseQue[reqId] == null) {
+
+                    while (Singletons.responseQue.getOrElse(reqId) { null } == null) {
                         TimeUnit.MILLISECONDS.sleep(100)
                         i++
                         if (i >= 600 * partStr.size) {
@@ -155,7 +137,7 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                             val endTime = System.nanoTime()
                             val duration =
                                 (endTime - startTime).toDouble() / 1000000 //divide by 1000000 to get milliseconds.
-                            LogManager.getLogger("client.$client")
+                            LogManager.getLogger("client-$client")
                                 .info("Request failed, No Response. Time: $duration  UA: " + req.getHeader("User-Agent") + " From: " + InetAddress.getLocalHost().hostAddress + " To: " + req.requestURL.toString() + "?" + req.queryString)
 
                             ClientHolder.addFailedRequest(client)
@@ -163,10 +145,10 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                         }
                     }
 
-                    val resFromSocket = Singletons.responseQue[reqId]
+                    val resFromSocket = Singletons.responseQue.getOrElse(reqId) { null }
 
-                    res.status = resFromSocket!!.statusCode
-                    resFromSocket.headers?.let {
+                    res.status = resFromSocket?.statusCode ?: 500
+                    resFromSocket?.headers?.let {
                         it.entries
                             .filter { f -> resFromSocket.statusCode < 400 || (resFromSocket.statusCode >= 400 && f.key == "Content-Type") }
                             .forEach { en ->
@@ -174,7 +156,7 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                             }
                     }
 
-                    resFromSocket.body?.let {
+                    resFromSocket?.body?.let {
                         res.outputStream.write(it)
                     }
 
@@ -184,7 +166,7 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                     val endTime = System.nanoTime()
 
                     val duration = (endTime - startTime).toDouble() / 1000000 //divide by 1000000 to get milliseconds.
-                    LogManager.getLogger("client.$client")
+                    LogManager.getLogger("client-$client")
                         .info("Request Success. Time: $duration  UA: " + req.getHeader("User-Agent") + " From: " + req.remoteAddr + " To: " + req.requestURL.toString() + "?" + req.queryString)
 
                     ClientHolder.addSuccessRequest(client, duration)
@@ -199,7 +181,7 @@ class BridgeFilter(private val template: SimpMessagingTemplate, val resourceLoad
                     Singletons.requestInstance.remove(reqId)
                     val endTime = System.nanoTime()
                     val duration = (endTime - startTime).toDouble() / 1000000 //divide by 1000000 to get milliseconds.
-                    LogManager.getLogger("client.$client")
+                    LogManager.getLogger("client-$client")
                         .info("Request failed, Unknown error. Time: $duration  UA: " + req.getHeader("User-Agent") + " From: " + InetAddress.getLocalHost().hostAddress + " To: " + req.requestURL.toString() + "?" + req.queryString)
                     ClientHolder.addFailedRequest(client)
                     return
@@ -256,9 +238,9 @@ class Resp(val body: ByteArray?, val statusCode: Int, val headers: Map<String, A
 
 object Singletons {
     //    val sendQueue: ConcurrentMap<String, MessageHandler> by lazy { ConcurrentHashMap<String, MessageHandler>() }
-    val responseQue: MutableMap<String, Resp> by lazy { mutableMapOf<String, Resp>() }
-    val requestInstance: MutableMap<String, RequestQue> by lazy { mutableMapOf<String, RequestQue>() }
-    val buildSocketChunkData: MutableMap<String, ChunkCollector> by lazy { mutableMapOf<String, ChunkCollector>() }
+    val responseQue: ConcurrentMap<String, Resp> by lazy { ConcurrentHashMap() }
+    val requestInstance: ConcurrentMap<String, RequestQue> by lazy { ConcurrentHashMap() }
+    val buildSocketChunkData: ConcurrentMap<String, ChunkCollector> by lazy { ConcurrentHashMap() }
 }
 
 class SocketChunkData(
@@ -270,117 +252,37 @@ class SocketChunkData(
 )
 
 class ChunkCollector(private val id: String) {
-    private val listSocketChunk = mutableListOf<SocketChunkData>()
-    fun add(dt: SocketChunkData) {
-        if (!listSocketChunk.any { it.part == dt.part }) {
-            listSocketChunk.add(dt)
-        }
-
-        if (dt.part == dt.totalPart - 1) {
-            val tStart = LocalDateTime.now()
-            fixedRateTimer("timer-$id", false, 20, 100) {
-                if (listSocketChunk.size == dt.totalPart) {
-                    val bodyList = listSocketChunk.sortedBy { it.part }.mapNotNull { it.body }
-                    var bd = ByteArray(0)
-                    bodyList.forEach { bd += it }
-                    Singletons.responseQue[id] = Resp(
+    private val mapSocketChunk: ConcurrentMap<Int, SocketChunkData> by lazy { ConcurrentHashMap() }
+
+    init {
+        val tStart = LocalDateTime.now()
+        fixedRateTimer("timer-$id", false, 20, 50) {
+            val listSocketChunk = mapSocketChunk.entries.sortedBy { it.key }.map { it.value }
+            if (listSocketChunk.size > 1 && listSocketChunk[0].totalPart == listSocketChunk.size) {
+                val sortedChunk = listSocketChunk.sortedBy { it.part }
+                val bodyList = sortedChunk.mapNotNull { it.body }
+                var bd = ByteArray(0)
+                bodyList.forEach { bd += it }
+                Singletons.responseQue.getOrPut(id) {
+                    Resp(
                         bd,
-                        dt.status,
-                        dt.header?.entries?.associate { Pair(it.key, it.value.toTypedArray()) }
+                        sortedChunk.last().status,
+                        listSocketChunk.firstOrNull { it.header != null }?.header?.entries?.associate {
+                            Pair(it.key, it.value.toTypedArray())
+                        }
                     )
-                    this.cancel()
-                }
-                if (Duration.between(tStart, LocalDateTime.now()).toMillis() > 6000) {
-                    this.cancel()
                 }
-            }
-        }
-    }
-}
-
-@Controller
-class SocketChecker {
-//    @MessageMapping("/notification/{id}")
-//    @SendTo("/topic/notification/{id}")
-//    @Throws(Exception::class)
-//    fun notification(@DestinationVariable("id") id: String, message: MutableMap<*, *>): MutableMap<*, *> {
-//        return mutableMapOf(Pair("Hi", "I'am Ok"))
-//    }
-
-    @MessageMapping("/hi")
-    @SendTo("/topic/healthCheck")
-    @Throws(Exception::class)
-    fun greeting(message: MutableMap<*, *>): MutableMap<*, *> {
-        return mutableMapOf(Pair("Hi", "I'am Ok"))
-    }
 
-    @MessageMapping("/response/{id}")
-    @SendTo("/topic/healthCheck")
-    @Throws(Exception::class)
-    fun responseMsg(message: SocketChunkData, @DestinationVariable("id") id: String): MutableMap<*, *> {
-        try {
-            LogManager.getLogger(this.javaClass).info("req sent ${message.part} of ${message.totalPart}")
-
-            if (message.totalPart == 1) {
-                Singletons.responseQue[id] = Resp(
-                    message.body,
-                    message.status,
-                    message.header?.entries?.map { Pair(it.key, it.value.toTypedArray()) }?.toMap()
-                )
-            } else {
-                var sc = Singletons.buildSocketChunkData[id]
-
-                if (sc == null) {
-                    Singletons.buildSocketChunkData[id] = ChunkCollector(id)
-                    sc = Singletons.buildSocketChunkData[id]
-                }
-                sc?.add(message)
+                this.cancel()
             }
-        } catch (e: Exception) {
-            e.printStackTrace()
-        }
-
-        return mutableMapOf(Pair("Hi", "I'am Ok"))
-    }
-}
-
-@RestController
-class BridgeRestController {
-    @PostMapping("/_response/{id}")
-    fun responseFromRest(@PathVariable("id") id: String, req: HttpServletRequest): String {
-        val objectMapper = ObjectMapper()
-        val typeRef: TypeReference<HashMap<String, Array<String>>> =
-            object : TypeReference<HashMap<String, Array<String>>>() {}
-        val body = IOUtils.toByteArray(req.getPart("body").inputStream)
-        Singletons.responseQue[id] = Resp(
-            body,
-            String(IOUtils.toByteArray(req.getPart("status").inputStream)).toInt(),
-            if (req.getPart("header") != null) {
-                objectMapper.readValue(String(IOUtils.toByteArray(req.getPart("header").inputStream)), typeRef)
-            } else {
-                null
+            if (Duration.between(tStart, LocalDateTime.now()).toMillis() > 10 * 60 * 1000) {
+                this.cancel()
             }
-        )
-
-        return "{\"success\":true}"
-    }
-
-    @GetMapping("/_request/{id}")
-    fun getResponseObj(@PathVariable("id") id: String): RequestBuilder {
-        if (Singletons.requestInstance[id] == null) {
-            throw Exception("not found")
         }
-        return Singletons.requestInstance[id]!!.requestBuilder
-    }
-
-    @GetMapping("/clientStat")
-    fun getClientData(): Map<String, Client> {
-        return ClientHolder.get()
     }
 
-    @GetMapping("/clientStat/{id}")
-    fun getClientDataOne(@PathVariable("id") id: String): Client? {
-        return ClientHolder.get()[id]
+    fun add(dt: SocketChunkData) {
+        mapSocketChunk.getOrPut(dt.part) { dt }
     }
 }
 

+ 137 - 0
src/main/kotlin/co/id/datacomsolusindo/ipphonebridge/BridgeRestController.kt

@@ -0,0 +1,137 @@
+package co.id.datacomsolusindo.ipphonebridge
+
+import com.fasterxml.jackson.core.type.TypeReference
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.apache.commons.io.IOUtils
+import org.springframework.http.MediaType
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PathVariable
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.RestController
+import java.util.HashMap
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
+
+@RestController
+class BridgeRestController {
+    @PostMapping("/_response/{id}")
+    fun responseFromRest(@PathVariable("id") id: String, req: HttpServletRequest): String {
+        val objectMapper = ObjectMapper()
+        val typeRef: TypeReference<HashMap<String, Array<String>>> =
+            object : TypeReference<HashMap<String, Array<String>>>() {}
+        val body = IOUtils.toByteArray(req.getPart("body").inputStream)
+        Singletons.responseQue.getOrPut(id) {
+            Resp(
+                body,
+                String(IOUtils.toByteArray(req.getPart("status").inputStream)).toInt(),
+                if (req.getPart("header") != null) {
+                    objectMapper.readValue(String(IOUtils.toByteArray(req.getPart("header").inputStream)), typeRef)
+                } else {
+                    null
+                }
+            )
+        }
+
+        return "{\"success\":true}"
+    }
+
+    @GetMapping("/_request/{id}")
+    fun getResponseObj(@PathVariable("id") id: String): RequestBuilder {
+        if (Singletons.requestInstance.getOrElse(id) { null } == null) {
+            throw Exception("not found")
+        }
+        val rb = Singletons.requestInstance.getOrElse(id) { null }?.requestBuilder
+        if (rb == null) {
+            throw Exception("not found")
+        } else {
+            return rb
+        }
+    }
+
+    private val logSetting = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+            "<Configuration status=\"INFO\" name=\"MyApp\" packages=\"\">\n" +
+            "    <Properties>\n" +
+            "        <Property name=\"LOG_PATTERN\">%d %p [%c{1}] %m%n</Property>\n" +
+            "        <Property name=\"APP_LOG_ROOT\">log</Property>\n" +
+            "    </Properties>\n" +
+            "\n" +
+            "    <Appenders>\n" +
+            "        <Console name=\"Console\" target=\"SYSTEM_OUT\" follow=\"true\">\n" +
+            "            <PatternLayout pattern=\"\${LOG_PATTERN}\"/>\n" +
+            "        </Console>\n" +
+            "\n" +
+            "        <RollingFile name=\"RollingFile\" fileName=\"\${APP_LOG_ROOT}/app/app.log\"\n" +
+            "                     filePattern=\"\${APP_LOG_ROOT}/app/\$\${date:yyyy - MM}/app-%d{yyyy-MM-dd}-%i.log.zip\">\n" +
+            "            <PatternLayout>\n" +
+            "                <Pattern>\${LOG_PATTERN}</Pattern>\n" +
+            "            </PatternLayout>\n" +
+            "            <LevelRangeFilter minLevel=\"INFO\" maxLevel=\"INFO\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n" +
+            "            <Policies>\n" +
+            "                <TimeBasedTriggeringPolicy/>\n" +
+            "                <SizeBasedTriggeringPolicy size=\"10 MB\"/>\n" +
+            "            </Policies>\n" +
+            "        </RollingFile>\n" +
+            "\n" +
+            "        <RollingFile name=\"RollingFileError\" fileName=\"\${APP_LOG_ROOT}/error/app-error.log\"\n" +
+            "                     filePattern=\"\${APP_LOG_ROOT}/error/\$\${date:yyyy - MM}/app-error-%d{yyyy-MM-dd}-%i.log.zip\">\n" +
+            "            <PatternLayout>\n" +
+            "                <Pattern>\${LOG_PATTERN}</Pattern>\n" +
+            "            </PatternLayout>\n" +
+            "            <LevelRangeFilter minLevel=\"FATAL\" maxLevel=\"WARN\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n" +
+            "            <Policies>\n" +
+            "                <TimeBasedTriggeringPolicy/>\n" +
+            "                <SizeBasedTriggeringPolicy size=\"10 MB\"/>\n" +
+            "            </Policies>\n" +
+            "        </RollingFile>        \n" +
+            "        [CLIENT-APPENDER]\n" +
+            "    </Appenders>\n" +
+            "    <Loggers>\n" +
+            "        <Root level=\"INFO\">\n" +
+            "            <AppenderRef ref=\"Console\"/>\n" +
+            "            <AppenderRef ref=\"RollingFile\"/>\n" +
+            "            <AppenderRef ref=\"RollingFileError\"/>\n" +
+            "        </Root>\n" +
+            "        <Logger name=\"co.id.datacomsolusindo.ipphonebridge\" additivity=\"false\" level=\"INFO\">\n" +
+            "            <AppenderRef ref=\"RollingFile\"/>\n" +
+            "            <AppenderRef ref=\"Console\"/>\n" +
+            "        </Logger>\n" +
+            "        [CLIENT-LOGGER]               \n" +
+            "    </Loggers>\n" +
+            "</Configuration>"
+
+    @GetMapping("/log-setting.xml", produces = [MediaType.APPLICATION_XML_VALUE])
+    fun getLogSetting(servletResponse: HttpServletResponse): String {
+        val appender = ClientHolder.get().entries.joinToString {
+            "<RollingFile name=\"ClientAct${it.value.number}\" fileName=\"\${APP_LOG_ROOT}/client/${it.value.number}/act.log\"\n" +
+                    "                     filePattern=\"\${APP_LOG_ROOT}/client/${it.value.number}/\$\${date:yyyy - MM}/act-%d{yyyy-MM-dd}-%i.log.zip\">\n" +
+                    "            <PatternLayout>\n" +
+                    "                <Pattern>\${LOG_PATTERN}</Pattern>\n" +
+                    "            </PatternLayout>\n" +
+                    "            <LevelRangeFilter minLevel=\"INFO\" maxLevel=\"INFO\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n" +
+                    "            <Policies>\n" +
+                    "                <TimeBasedTriggeringPolicy/>\n" +
+                    "                <SizeBasedTriggeringPolicy size=\"10 MB\"/>\n" +
+                    "            </Policies>\n" +
+                    "        </RollingFile>"
+
+        }
+        val logger = ClientHolder.get().entries.joinToString {
+            "<Logger name=\"client-${it.value.number}\" additivity=\"false\" level=\"INFO\">\n" +
+                    "            <AppenderRef ref=\"ClientAct${it.value.number}\"/>\n" +
+                    "            <AppenderRef ref=\"Console\"/>\n" +
+                    "        </Logger> "
+        }
+
+        return logSetting.replace("[CLIENT-APPENDER]", appender).replace("[CLIENT-LOGGER]", logger)
+    }
+
+    @GetMapping("/clientStat")
+    fun getClientData(): Map<String, Client> {
+        return ClientHolder.get()
+    }
+
+    @GetMapping("/clientStat/{id}")
+    fun getClientDataOne(@PathVariable("id") id: String): Client? {
+        return ClientHolder.get()[id]
+    }
+}

+ 77 - 67
src/main/kotlin/co/id/datacomsolusindo/ipphonebridge/IpPhoneBridgeApplication.kt

@@ -15,6 +15,7 @@ import org.apache.logging.log4j.core.config.builder.api.RootLoggerComponentBuild
 import org.ini4j.Wini
 import org.springframework.boot.SpringApplication
 import org.springframework.boot.autoconfigure.SpringBootApplication
+import org.springframework.boot.context.event.ApplicationReadyEvent
 import org.springframework.context.event.EventListener
 import org.springframework.messaging.simp.stomp.StompHeaderAccessor
 import org.springframework.messaging.support.GenericMessage
@@ -25,6 +26,7 @@ import org.springframework.web.socket.messaging.SessionDisconnectEvent
 import org.springframework.web.socket.messaging.SessionSubscribeEvent
 import java.io.File
 import java.io.Serializable
+import java.net.URI
 import java.time.LocalDateTime
 import java.time.format.DateTimeFormatter
 import java.util.*
@@ -47,7 +49,7 @@ fun main(args: Array<String>) {
         properties["server.port"] = System.getenv("PORT")
     }
     if (properties["server.port"] == null) {
-        println("undefined port")
+//        println("undefined port")
         exitProcess(1)
     }
 
@@ -55,15 +57,18 @@ fun main(args: Array<String>) {
 
     sApp.setDefaultProperties(properties)
     sApp.run(*args)
+    //Configurator.reconfigure(URI("http://127.0.0.1:9090/log-setting.xml"))
     LogManager.getLogger("co.id.datacomsolusindo.ipphonebridge.IpPhoneBridgeApplication").info("Bridge Start")
     println("hostname ${System.getenv("HOSTNAME")}")
     println("token ${System.getenv("KUBE_TOKEN")}")
     println("service_host ${System.getenv("KUBERNETES_SERVICE_HOST")}")
     println("port ${System.getenv("KUBERNETES_PORT_443_TCP_PORT")}")
 
-    val command = "curl -X GET https://${System.getenv("KUBERNETES_SERVICE_HOST")}:${System.getenv("KUBERNETES_PORT_443_TCP_PORT")}/api/v1/namespaces/tm-bridge/pods/${System.getenv("HOSTNAME")}"
-    val process: Process = Runtime.getRuntime().exec(command)
-    println(String(process.inputStream.readAllBytes()))
+//    val command =
+//        "curl -X GET https://${System.getenv("KUBERNETES_SERVICE_HOST")}:${System.getenv("KUBERNETES_PORT_443_TCP_PORT")}/api/v1/namespaces/tm-bridge/pods/${
+//            System.getenv("HOSTNAME")
+//        }"
+
 }
 
 class Client(
@@ -135,66 +140,71 @@ object ClientHolder {
 
 @Component
 class WebSocketEventListener {
-    fun logBuilder(clNum: String) {
-        val builder = ConfigurationBuilderFactory.newConfigurationBuilder()
-        val console = builder.newAppender("stdout", "Console")
-
-        val appLog = builder.newAppender("appLog", "RollingFile")
-        appLog.addAttribute("fileName", "log/app/app.log")
-        appLog.addAttribute("filePattern", "log/app/\$\${date:yyyy - MM}/app-%d{yyyy-MM-dd}-%i.log.zip")
-
-        val flow: FilterComponentBuilder = builder.newFilter(
-            "MarkerFilter",
-            Filter.Result.ACCEPT,
-            Filter.Result.DENY
-        )
-        flow.addAttribute("marker", "FLOW")
-        console.add(flow)
-        val standard = builder.newLayout("PatternLayout")
-        standard.addAttribute("pattern", "%d %p [%c{1}] %m%n")
-        val policies = builder.newLayout("Policies")
-        val timeBasedTriggeringPolicy = builder.newLayout("TimeBasedTriggeringPolicy")
-        val sizeBasedTriggeringPolicy = builder.newLayout("SizeBasedTriggeringPolicy")
-
-        sizeBasedTriggeringPolicy.addAttribute("size", "10 MB")
-        policies.addComponent(timeBasedTriggeringPolicy)
-        policies.addComponent(sizeBasedTriggeringPolicy)
-        console.add(standard)
-        builder.add(console)
-
-        appLog.add(standard)
-        appLog.addComponent(policies)
-        builder.add(appLog)
-
-        val rootLogger: RootLoggerComponentBuilder = builder.newRootLogger(Level.INFO)
-        rootLogger.add(builder.newAppenderRef("stdout"))
-        builder.add(rootLogger)
-
-        val logger: LoggerComponentBuilder = builder.newLogger("co.id.datacomsolusindo.ipphonebridge", Level.DEBUG)
-        logger.add(builder.newAppenderRef("appLog"))
-        logger.addAttribute("additivity", false)
-        builder.add(logger)
-        rootLogger.add(builder.newAppenderRef("appLog"))
-
-        ClientHolder.get().entries.forEach {
-            val clientLog = builder.newAppender("client-${it.key}", "RollingFile")
-            clientLog.addAttribute("fileName", "log/${it.key}/client-${it.key}.log")
-            clientLog.addAttribute(
-                "filePattern",
-                "log/${it.key}/\$\${date:yyyy - MM}/app-%d{yyyy-MM-dd}-%i.client-${it.key}.zip"
-            )
-            clientLog.add(standard)
-            clientLog.addComponent(policies)
-            builder.add(clientLog)
-
-            val loggerClient: LoggerComponentBuilder = builder.newLogger("client.${it.key}", Level.DEBUG)
-            loggerClient.add(builder.newAppenderRef("client-${it.key}"))
-            loggerClient.addAttribute("additivity", false)
-            builder.add(loggerClient)
-            rootLogger.add(builder.newAppenderRef("client-${it.key}"))
-        }
+    @EventListener(ApplicationReadyEvent::class)
+    fun doSomethingAfterStartup() {
+        Configurator.reconfigure(URI("http://127.0.0.1:9090/log-setting.xml"))
+    }
 
-        Configurator.reconfigure(builder.build())
+    fun logBuilder(clNum: String) {
+//        val builder = ConfigurationBuilderFactory.newConfigurationBuilder()
+//        val consoleAppender = builder.newAppender("stdout", "Console")
+//
+//        val appLog = builder.newAppender("appLog", "RollingFile")
+//        appLog.addAttribute("fileName", "log/app/app.log")
+//        appLog.addAttribute("filePattern", "log/app/\$\${date:yyyy - MM}/app-%d{yyyy-MM-dd}-%i.log.zip")
+//
+//        val flow: FilterComponentBuilder = builder.newFilter(
+//            "MarkerFilter",
+//            Filter.Result.ACCEPT,
+//            Filter.Result.DENY
+//        )
+//        flow.addAttribute("marker", "FLOW")
+//        consoleAppender.add(flow)
+//        val standard = builder.newLayout("PatternLayout")
+//        standard.addAttribute("pattern", "%d %p [%c{1}] %m%n")
+//        val policies = builder.newLayout("Policies")
+//        val timeBasedTriggeringPolicy = builder.newLayout("TimeBasedTriggeringPolicy")
+//        val sizeBasedTriggeringPolicy = builder.newLayout("SizeBasedTriggeringPolicy")
+//
+//        sizeBasedTriggeringPolicy.addAttribute("size", "10 MB")
+//        policies.addComponent(timeBasedTriggeringPolicy)
+//        policies.addComponent(sizeBasedTriggeringPolicy)
+//        consoleAppender.add(standard)
+//        builder.add(consoleAppender)
+//
+//        appLog.add(standard)
+//        appLog.addComponent(policies)
+//        builder.add(appLog)
+//
+//        val rootLogger: RootLoggerComponentBuilder = builder.newRootLogger(Level.INFO)
+//        rootLogger.add(builder.newAppenderRef("stdout"))
+//        builder.add(rootLogger)
+//
+//        val logger: LoggerComponentBuilder = builder.newLogger("co.id.datacomsolusindo.ipphonebridge", Level.DEBUG)
+//        logger.add(builder.newAppenderRef("appLog"))
+//        logger.addAttribute("additivity", false)
+//        builder.add(logger)
+//        rootLogger.add(builder.newAppenderRef("appLog"))
+//
+//        ClientHolder.get().entries.forEach {
+//            val clientLog = builder.newAppender("client-${it.key}", "RollingFile")
+//            clientLog.addAttribute("fileName", "log/${it.key}/client-${it.key}.log")
+//            clientLog.addAttribute(
+//                "filePattern",
+//                "log/${it.key}/\$\${date:yyyy - MM}/app-%d{yyyy-MM-dd}-%i.client-${it.key}.zip"
+//            )
+//            clientLog.add(standard)
+//            clientLog.addComponent(policies)
+//            builder.add(clientLog)
+//
+//            val loggerClient: LoggerComponentBuilder = builder.newLogger("client-${it.key}", Level.DEBUG)
+//            loggerClient.add(builder.newAppenderRef("client-${it.key}"))
+//            loggerClient.addAttribute("additivity", false)
+//            builder.add(loggerClient)
+//            rootLogger.add(builder.newAppenderRef("client-${it.key}"))
+//        }
+
+        Configurator.reconfigure(URI("http://127.0.0.1:9090/log-setting.xml"))
     }
 
     //    @EventListener
@@ -210,13 +220,13 @@ class WebSocketEventListener {
     fun onConnect(event: SessionConnectEvent) {
         val accessor = StompHeaderAccessor.wrap(event.message)
         val sessionId = accessor.sessionId
-        println("connect with session id $sessionId")
+        AppLog.write(this.javaClass).info("connect with session id $sessionId")
 
     }
 
     @EventListener
     fun onDisconnect(event: SessionDisconnectEvent) {
-        println("disconnect with session id ${event.sessionId}")
+        AppLog.write(this.javaClass).info("disconnect with session id ${event.sessionId}")
     }
 
     @EventListener
@@ -225,7 +235,7 @@ class WebSocketEventListener {
         val simDestination = message.headers["simpDestination"] as String?
         val accessor = StompHeaderAccessor.wrap(event.message)
         val sessionId = accessor.sessionId
-        println("subscribe to $simDestination with session id $sessionId")
+        AppLog.write(this.javaClass).info("subscribe to $simDestination with session id $sessionId")
 
 
         if (!(simDestination!!.startsWith("/topic/healthCheck") || simDestination.startsWith("/topic/notification"))) {
@@ -241,7 +251,7 @@ class WebSocketEventListener {
 
             LogManager.getLogger(this.javaClass).info("clientConnected $simDestination")
             logBuilder(clNum)
-            LogManager.getLogger("client.$clNum").info("Client $clNum Connected")
+            LogManager.getLogger("client-$clNum").info("Client $clNum Connected")
         }
     }
 }

+ 52 - 0
src/main/kotlin/co/id/datacomsolusindo/ipphonebridge/SocketChecker.kt

@@ -0,0 +1,52 @@
+package co.id.datacomsolusindo.ipphonebridge
+
+import org.apache.logging.log4j.LogManager
+import org.springframework.messaging.handler.annotation.DestinationVariable
+import org.springframework.messaging.handler.annotation.MessageMapping
+import org.springframework.messaging.handler.annotation.SendTo
+import org.springframework.stereotype.Controller
+
+@Controller
+class SocketChecker {
+//    @MessageMapping("/notification/{id}")
+//    @SendTo("/topic/notification/{id}")
+//    @Throws(Exception::class)
+//    fun notification(@DestinationVariable("id") id: String, message: MutableMap<*, *>): MutableMap<*, *> {
+//        return mutableMapOf(Pair("Hi", "I'am Ok"))
+//    }
+
+    @MessageMapping("/hi")
+    @SendTo("/topic/healthCheck")
+    @Throws(Exception::class)
+    fun greeting(message: MutableMap<*, *>): MutableMap<*, *> {
+        return mutableMapOf(Pair("Hi", "I'am Ok"))
+    }
+
+    @MessageMapping("/response/{id}")
+    @SendTo("/topic/healthCheck")
+    @Throws(Exception::class)
+    fun responseMsg(message: SocketChunkData, @DestinationVariable("id") id: String): MutableMap<*, *> {
+        try {
+//            LogManager.getLogger(this.javaClass).info("req sent ${message.part} of ${message.totalPart}")
+//            println("req sent ${message.part} of ${message.totalPart}")
+            if (message.totalPart == 1) {
+//                println("one part only with id $id")
+                Singletons.responseQue.getOrPut(id) {
+                    Resp(
+                        message.body,
+                        message.status,
+                        message.header?.entries?.associate { Pair(it.key, it.value.toTypedArray()) }
+                    )
+                }
+//                println("status code " + Singletons.responseQue[id]?.statusCode ?: "unknown code")
+            } else {
+                val sc = Singletons.buildSocketChunkData.getOrPut(id) { ChunkCollector(id) }
+                sc.add(message)
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+
+        return mutableMapOf(Pair("Hi", "I'am Ok"))
+    }
+}