如何在 Ktor 中访问用户定义的环境变量

问题描述 投票:0回答:1

我使用 ktor 作为网络服务器。用户调用 Kotlin Clikt 命令来启动服务器,并向其传递一个稍后在后端处理某些 REST 请求时需要的变量。

然后,clikt 类启动服务器时采用单个参数,并且在启动嵌入式服务器时传递该参数。该代码在这里:

class StartServer : CliktCommand(help = "Starts PHGv2 BrAPI Server") {

    private val myLogger = LogManager.getLogger(StartServer::class.java)
    val dbPath by option(help = "Full path to folder where TileDB datasets are stored.   ")
        .default("")
        .validate {
            require(it.isNotBlank()) {
                "--db-path must not be blank"
            }
        }

    override fun run() {
        setupDebugLogging()

        // Verify the uri is valid.  We only care about the hvcf dataset,
        // so check that one explicitly
        val hvcfExists = verifyURI(dbPath,"hvcf_dataset")
        if (!hvcfExists) {
            myLogger.error("hvcf_dataset does not exist in $dbPath.  Exiting.")
            return
        }

        // Create an Args list to pass to the server
        // This tells the endpoint code where the datasets are located.
        val dbUri = "-P:TILEDB_URI=${dbPath}"
        val args = arrayOf(dbUri)

        // commandLineEnvironment reads the application.config file
        // https://ktor.io/docs/configuration.html#hocon-file
        embeddedServer(Netty, commandLineEnvironment(args)).start(wait = true)
    }
}

后来,当服务需要此配置变量的查询时,我有以下代码:

private val config = HoconApplicationConfig(ConfigFactory.load())

//val tiledbURI = environment.config.property("TILEDB_URI").getString()
val tiledbURI = config.property("TILEDB_URI").getString()

object SamplesService {

    private val myLogger = LogManager.getLogger(SamplesService::class.java)

    // Cached map of all taxa. Key is genoid mapped to Sample object
    private val taxa: Map<String, Sample> by lazy {
        taxaMap("${tiledbURI}/hvcf_dataset")
    }
     ....

tiledbURI 的值始终为 null(但代码可以编译)。 如果我按照文档中的示例进行操作,它会显示从环境中获取值:

val tiledbURI = environment.config.property("TILEDB_URI").getString()

但是“环境”未知,无法编译。是否需要不同的导入?我的相关进口是:

import com.typesafe.config.ConfigFactory
import io.ktor.server.config.*

我错过了进口吗?或者这个变量只是为了启动服务器而存在,并且它们没有存储在配置文件中以供进一步访问?

更新/编辑:

hcon 配置文件是这样的:

callsPageSize=10
variantsPageSize=100

# For connecting to tiledb from ktor.  Users should un-comment
# and edit the TILEDB_URI variable to point to their tiledb folder
# When running junit tests,  replace ""/Users/lcj34" in the example below
# with the  path to your home directory.  The path should end with a /
# For other use cases, replace the path with the path to the tiledb folder
#TILEDB_URI="/Users/lcj34/temp/phgv2Tests/tempDir/testTileDBURI/"

# Server metadata params  You will need to fill these out to match your setup
contactEmail = "[email protected]"
documentationURL = "https://github.com/maize-genetics/phg_v2"
location = "Ithaca NY"
organizationName = "Institute for Genetic Diversity at Cornell University"
organizationURL = "https://www.maizegenetics.net/"
serverDescription = "Server to connect to the Maize PHG Tiledb through BrAPI calls."
serverName = "Maize  PHGv2"

ktor {
    deployment {
        port = 8080
        watch = [  build ]
    }
    application {
        modules = [ net.maizegenetics.phgv2.brapi.ApplicationKt.module ]
    }
}

注意注释掉的 TILEDB_URI 变量。运行我们应用程序的用户无法轻松访问配置文件,因为它捆绑在一个 fat jar 中。与更新配置文件中的 TILEDB_URI 变量相关的注释主要用于开发人员 junit 测试。

我们需要的是用户能够向我们传递一个我们可以为此参数设置的值。

config environment ktor
1个回答
0
投票

我可以通过进行以下更改来使其正常工作。基本上,我将用户参数传递给 ktor 路由代码。上面显示的文件更改如下:

class StartServer : CliktCommand(help = "Starts PHGv2 BrAPI Server") {

    private val myLogger = LogManager.getLogger(StartServer::class.java)
    val dbPath by option(help = "Full path to folder where TileDB datasets are stored.   ")
        .default("")
        .validate {
            require(it.isNotBlank()) {
                "--db-path must not be blank"
            }
        }

    override fun run() {
        setupDebugLogging()

        // Verify the uri is valid.  We only care about the hvcf dataset,
        // so check that one explicitly
        val hvcfExists = verifyURI(dbPath,"hvcf_dataset")
        if (!hvcfExists) {
            myLogger.error("hvcf_dataset does not exist in $dbPath.  Exiting.")
            return
        }

        // Create an Args list to pass to the server
        // This tells the endpoint code where the datasets are located.
        val dbUri = "-P:TILEDB_URI=${dbPath}"
        //val dbUri = "TILEDB_URI=${dbPath}"
        val args = arrayOf(dbUri)

        val server = embeddedServer(Netty,port=8080) {
            module(args)
        }
        server.start(true)

    }

}

然后在 Application.kt 中通过以下方式处理:

fun Application.module(args:Array<String>) {

    install(DefaultHeaders)
    install(CallLogging)

    install(ContentNegotiation) {
        json(Json {
            prettyPrint = false
            isLenient = true
            encodeDefaults = true
        })
    }


    // Setup routing.  Individual endpoints create Kotlin Route extensions
    // to handle processing REST requests.

    routing {
        // this method routes brapi/v2/
        // Within apiRoute(), specific endpoint calls are handled
        apiRoute(args)
    }

}

我们继续传递这个参数,直到它到达实际处理数据的函数:

fun Route.samples(args:Array<String>) {

    val samplesService = SamplesService
    val tiledbURI = args[0].substringAfter("TILEDB_URI=").substringBefore(" ")

    route("/samples") {

        get("") {
            call.respond(
                SampleListResponse(
                    Metadata(),
                    SampleListResponseResult(samplesService.lcjAllTaxaNames(tiledbURI).toTypedArray())
                    
                )
            )
        }

    }
}

如果有更好的方法来传递参数值,请告诉我,但这目前有效。

© www.soinside.com 2019 - 2024. All rights reserved.