Я пытаюсь подключиться к IMAP-серверу с необработанными сокетами Ktor
@KtorExperimentalAPI
override suspend fun start(host: SocketAddress) {
socket = aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(host).tls(Dispatchers.IO)
writeChannel = socket.openWriteChannel()
readChannel = socket.openReadChannel()
val handshakeResponse = ByteArray(readChannel.availableForRead)
readChannel.readAvailable(handshakeResponse)
val handshake = String(handshakeResponse)
println(handshake)
}
После этого подключения я ожидаю, что получу ответ сервера IMAP, подобный этому
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SPECIAL-USE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
И затем я посылаю команды IMAP для входа в мой почтовый ящик
@KtorExperimentalAPI
override suspend fun command(command: String): String {
writeChannel.write("$command\r\n".also { print(it) })
val response = ByteArray(readChannel.availableForRead)
readChannel.readAvailable(response)
val responseString = String(response)
println(responseString)
return responseString
}
Таким образом, мой вывод должен быть таким
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SPECIAL-USE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
S1 LOGIN email pass
S1 OK Logged in
Но по какой-то причине вывод выглядит так, как будто эти команды выполняются параллельно threads
S1 LOGIN email pass
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SPECIAL-USE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
И моя сопрограмма заблокирована на каналах записи / чтения, потому что Ktor использует рандомные каналы, и я не могу записать на канал, пока не прочту вывод
Мой основной код выглядит следующим образом
fun run() {
val store = IMAPStore()
runBlocking(coroutineContext) {
//connect with tls (suspend function)
store.install()
//send login command (suspend function)
store.login()
}
}
Я, наверное, не совсем понимаю, как работает соединение через tls и как работают каналы. Может быть, я неправильно запускаю сопрограммы.
В этом примере кода тот же лог c отлично работает
fun main() {
runBlocking {
val socket =
aSocket(ActorSelectorManager(Dispatchers.IO)).tcp().connect(host)
.tls(Dispatchers.IO)
val w = socket.openWriteChannel(autoFlush = false)
val r = socket.openReadChannel()
r.readUTF8LineTo(System.out)
w.write("$TAG${tagCounter++} LOGIN email password\r\n")
r.readUTF8LineTo(System.out)
}
Может кто-то понять и объяснить это поведение?