Kotlin/NativeでHTTPサーバーを作るアドベントカレンダー(20日目:ポート番号変更)

この記事はkdnaktの1人 Advent Calendar 202020日目の記事です(1日遅れ)。

 

2020年は会社でKotlin dojoを主催して週1回30分Kotlinと戯れていました。12月はその集大成ということで、Kotlin/NativeでHTTPサーバーを作ってみたいと思います。どこまでできるか、お楽しみ……。

 

 

[kotlinx-cli]

19日目はPOSTメソッドへ対応するために、リクエストヘッダーをKotlinオブジェクトにパースする実装を行いました。引き続きPOSTメソッドの実装を進めたいところですが、GETメソッドと処理を分岐させる部分が出てくるため、既存のmain()関数内の処理がデグレードを起こさないか心配です。

 

そこで、main()関数内の処理を外部からテストするために、テスト用のポートでHTTPサーバーを起動できるようにします。

 

HTTPサーバーの起動時に、kttpd.kexe -p 3000のように引数を渡してポート番号を変更するために、kotlinx-cliを利用できるようにします。

github.com

 

README.mdに記載のとおり、build.gradle.ktsに1行追加します。

kotlin {
    macosX64("native") {
+         // For kotlinx-cli
+         compilations["main"].enableEndorsedLibs = true
        binaries {
            executable {
                entryPoint = "com.kdnakt.kttpd.main"
            }
        }
    }
}

 

引き続き、README.mdの記載を参考にArgParserクラスを利用する処理を追加します*1

 

[ポート番号を引数で受け取る]

ソケットのポート番号を指定する部分のコードは以下のようになっています。

with(serverAddr) {
    memset(this.ptr, 0, sizeOf<sockaddr_in>().convert())
    sin_family = AF_INET.convert()
    sin_addr.s_addr = posix_htons(0).convert()
    sin_port = posix_htons(port).convert()
}

 

ここで利用されているposix_htons関数はShort型の引数をとります。

f:id:kidani_a:20201221050633p:plain

 

しかし、kotlinx-cliでは、以下の型の引数しかデフォルトでは用意されていません。

  • ArgType.Boolean
  • ArgType.Int
  • ArgType.String
  • ArgType.Double
  • ArgType.Choice

 

独自のArgTypeを定義することもできるようですが、Int型のArgTypeを利用して進めます。

 

ArgParserの第一引数はval programName: Stringなので任意の文字列を入れることができます。

kotlinx-cli/ArgParser.kt at master · Kotlin/kotlinx-cli · GitHub

 

あとは、移譲(Delegation)を利用して起動時引数を定義してArgParser.parse()を呼び出し、定義した引数を利用します。

fun main(args: Array) {
    val argsParser = ArgParser("kttpd")
    val port by argsParser.option(ArgType.Int, shortName="p").default(8080)
    argsParser.parse(args)

    // 省略
    with(serverAddr) {
        memset(this.ptr, 0, sizeOf<sockaddr_in>().convert())
        sin_family = AF_INET.convert()
        sin_addr.s_addr = posix_htons(0).convert()
        sin_port = posix_htons(port.toShort()).convert()
    }
}

 
これで、起動時引数を利用することができるようになりました。

まずはヘルプを確認してみます。

$ ./build/bin/native/releaseExecutable/kttpd.kexe -h
Usage: kttpd options_list
Options: 
    --port, -p [8080] { Int }
    --help, -h -> Usage info 

 

雑ですが、kotlinx-cliがデフォルトで提供している形でヘルプが表示されました。定義した変数名がそのまま起動時引数の正式名称として利用できるようです。

 

次に、ポート指定でのHTTPサーバーの起動を試します。

$ ./build/bin/native/releaseExecutable/kttpd.kexe --port 1234
kttpd start!

 

ブラウザでhttp://localhost:1234/index.htmlにアクセスすると、無事index.htmlの内容が表示されました。

f:id:kidani_a:20201221100006p:plain

 

[まとめ]

  • Kotlin/Nativeの場合、kotlinx-cliを利用するための設定変更は1行で済む
  • kotlinx-cliを利用してヘルプを表示した
  • kotlinx-cliを利用して、HTTPサーバーのポートを起動時に指定可能とした
  • 実装中のコードは以下のリポジトリにまとめてある

github.com

 

*1:以下の画像のようにコンパイルエラーが出る場合は、gradle clean buildなどのコマンドで解消する場合があります。 

f:id:kidani_a:20201221050538p:plain