refactor syslog server to use Dispatchers.IO and SupervisorScope (try to fix connection refused error)
This commit is contained in:
parent
71386ded3b
commit
0f9e51df31
1 changed files with 32 additions and 38 deletions
|
|
@ -16,12 +16,12 @@ import io.ktor.utils.io.readUTF8Line
|
||||||
import java.util.EnumSet
|
import java.util.EnumSet
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.coroutineScope
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.asSharedFlow
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
|
|
||||||
|
|
@ -56,53 +56,47 @@ class SyslogSocketServer(
|
||||||
get() = _messages.asSharedFlow()
|
get() = _messages.asSharedFlow()
|
||||||
|
|
||||||
|
|
||||||
suspend fun start(): Unit = coroutineScope {
|
suspend fun start(): Unit = withContext(Dispatchers.IO) {
|
||||||
log("started listening: ${serverSocketTcp.localAddress}")
|
log("started listening: ${serverSocketTcp.localAddress}")
|
||||||
|
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val socket: Socket = serverSocketTcp.accept()
|
val socket: Socket = serverSocketTcp.accept()
|
||||||
log("new socket ${socket.description()}")
|
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
val channel = socket.openReadChannel()
|
log("new socket ${socket.description()}")
|
||||||
try {
|
handleConnection(socket)
|
||||||
while (socket.socketContext.isActive && !channel.isClosedForRead) {
|
|
||||||
val line = runCatching {
|
|
||||||
channel.readUTF8Line()
|
|
||||||
}.fold(
|
|
||||||
onSuccess = { line ->
|
|
||||||
if (line == null) {
|
|
||||||
log("received 'null' from ${socket.description()} - closing connection")
|
|
||||||
socket.close()
|
|
||||||
}
|
|
||||||
// log("received '$line' from ${socket.description()}")
|
|
||||||
line
|
|
||||||
},
|
|
||||||
onFailure = { ex ->
|
|
||||||
if (ex is CancellationException) throw ex
|
|
||||||
|
|
||||||
log("reading line from socket failed ${socket.description()}, cause: $ex")
|
|
||||||
null
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if (line != null) {
|
|
||||||
val syslog = SyslogMsg(syslogParser.parseLine(line))
|
|
||||||
_messages.emit(syslog)
|
|
||||||
}
|
|
||||||
yield()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (e is CancellationException) throw e
|
|
||||||
log("closing socket ${socket.description()}, cause: ${e::class.java.name} ${e.message}")
|
|
||||||
e.printStackTrace()
|
|
||||||
withContext(Dispatchers.IO) { socket.close() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
yield()
|
yield()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun handleConnection(
|
||||||
|
socket: Socket
|
||||||
|
) = supervisorScope {
|
||||||
|
try {
|
||||||
|
val channel = socket.openReadChannel()
|
||||||
|
while (socket.socketContext.isActive && !channel.isClosedForRead) {
|
||||||
|
|
||||||
|
val line = channel.readUTF8Line()
|
||||||
|
|
||||||
|
requireNotNull(line) {
|
||||||
|
"received 'null' line from ${socket.description()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val syslog = SyslogMsg(syslogParser.parseLine(line))
|
||||||
|
_messages.emit(syslog)
|
||||||
|
|
||||||
|
yield()
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
if (e is CancellationException) throw e
|
||||||
|
log("closing socket ${socket.description()}, cause: ${e::class.java.name} ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
|
withContext(Dispatchers.IO) { socket.close() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun log(msg: String) = println("[SyslogSocketServer] $msg")
|
private fun log(msg: String) = println("[SyslogSocketServer] $msg")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue