今週は第45回を開催しました。引き続きKotlin Hands-on編です!
前回の様子はコチラ↓
[第45回の様子]
2020/12/23に第45回を開催した。
参加メンバーは自分をいれて5名。1ヶ月ぶりくらいに参戦してくれたメンバーも
勉強会本編の内容としては、前回に引き続きCreating a WebSocket Chat with Ktorハンズオンに取り組み、5章Creating the chat clientを終えて、本ハンズオンを最後まで完了した。
2020年のうちに終えられて良かった!🎉
[学んだことや疑問点]
- Creating a WebSocket Chat with Ktor: 5. Creating the chat client
- 前回作ったサーバーに接続するためのチャットクライアントを実装する
- 最初のバージョンでは、クライアントがメッセージを送信すると、次のメッセージを受信できる(自分からのメッセージの可能性もある)という残念な実装だった
- 残念ではあるけれども、KtorのWebSocket機構がCoroutineのサスペンドの仕組みを使っているので、
runBlockingブロックで囲む必要があることを学んだ - 残念な実装は、
suspend修飾子を使って入出力の処理をそれぞれ別の関数に分割することで改善できた suspend関数を呼び出すときにはlaunchブロックを使い、処理の終了を待つ場合はlaunchブロックのJob型の戻り値を利用すればよい
@KtorExperimentalAPI
fun main() {
val client = HttpClient {
install(WebSockets)
}
runBlocking {
client.webSocket(method = HttpMethod.Get, host = "127.0.0.1", port = 8080, path = "/chat") {
val messageOutputRoutine = launch { outputMessages() }
val userInputRoutine = launch { inputMessages() }
userInputRoutine.join() // Wait for completion; either "exit" or error
messageOutputRoutine.cancelAndJoin()
}
}
client.close()
println("Connection closed. Goodbye!")
}
suspend fun DefaultClientWebSocketSession.inputMessages() {
while (true) {
val message = readLine() ?: ""
if (message.equals("exit", true)) return
try {
send(message)
} catch (e: Exception) {
println("Error while sending: " + e.localizedMessage)
return
}
}
}
suspend fun DefaultClientWebSocketSession.outputMessages() {
try {
for (message in incoming) {
message as? Frame.Text ?: continue
println(message.readText())
}
} catch (e: Exception) {
println("Error while receiving: " + e.localizedMessage)
}
}
- 本筋とはあまり関係ないが、IntelliJで同じプロジェクト内の同じKotlinアプリを2つ同時に動かす場合(今回のように、チャットクライアントを2つ起動するような場合)、以下の警告が表示されて同時起動ができなかった

- 追加で、画面右上から実行時の設定を変更し、「Allow parallel run」にチェックを入れる必要があった

[まとめ]
モブプログラミング・スタイルで、WebSocket Chat with Ktorハンズオンを終了した。
IntelliJの使い方も学べたし、Coroutineに少し触れることができて良かった。2021年は本格的にCoroutineについて学んでいくぞ!
今週の進捗は以下のプルリクエストにまとまっている。