Repository: JetBrains/compose-multiplatform
File: benchmarks/multiplatform/benchmarks/src/desktopMain/kotlin/BenchmarksSaveServer.kt (Kotlin)

Code before:
    val name: String,
    val stats: String // JSON string of BenchmarkStats
)

/**
 * Starts a Ktor server to receive benchmark results from browsers
 * and save them to disk in the same format as the direct disk saving mechanism.
 */
object BenchmarksSaveServer {
    private var server: EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration>? = null

    fun start(port: Int = BENCHMARK_SERVER_PORT) {
        if (server != null) {
            println("Benchmark server is already running")
            return
        }

        server = embeddedServer(Netty, port = port) {
            install(ContentNegotiation) {
                json()
            }
            install(CORS) {
                allowMethod(HttpMethod.Get)
                allowMethod(HttpMethod.Post)
                allowHeader(HttpHeaders.ContentType)
                allowHost("localhost:8080")
            }
            routing {
                post("/benchmark") {
                    val result = call.receive<BenchmarkResultFromClient>()
                    if (result.name.isEmpty()) {
                        println("Stopping server! Received empty name from client")
                        call.respond(HttpStatusCode.OK, "Server stopped.")
                        stop()
                        return@post
                    }
                    println("Received benchmark result for: ${result.name}")

                    withContext(Dispatchers.IO) {
                        if (Config.saveStatsToJSON) {
                            val jsonPath = Path("build/benchmarks/json-reports/${result.name}.json")
                            SystemFileSystem.createDirectories(jsonPath.parent!!)
                            SystemFileSystem.sink(jsonPath).writeText(result.stats)
                            println("JSON results saved to ${SystemFileSystem.resolve(jsonPath)}")
                        }

                        if (Config.saveStatsToCSV) {
                            // TODO: for CSV, we would need to convert JSON to the values
                            println("CSV results are not yet supported for the browser.")
                        }
                    }

Review comment (suggestion):
perhaps using `anyHost()` would help avoid the collisions when the web benchmarks run on a different port?

https://ktor.io/docs/server-cors.html#hosts

Code after:
    val name: String,
    val stats: String // JSON string of BenchmarkStats
)

/**
 * Starts a Ktor server to receive benchmark results from browsers
 * and save them to disk in the same format as the direct disk saving mechanism.
 */
object BenchmarksSaveServer {
    private var server: EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration>? = null

    fun start(port: Int = BENCHMARK_SERVER_PORT) {
        if (server != null) {
            println("Benchmark server is already running")
            return
        }

        server = embeddedServer(Netty, port = port) {
            install(ContentNegotiation) {
                json()
            }
            install(CORS) {
                allowMethod(HttpMethod.Get)
                allowMethod(HttpMethod.Post)
                allowHeader(HttpHeaders.ContentType)
                anyHost()
            }
            routing {
                post("/benchmark") {
                    val result = call.receive<BenchmarkResultFromClient>()
                    if (result.name.isEmpty()) {
                        println("Stopping server! Received empty name from client")
                        call.respond(HttpStatusCode.OK, "Server stopped.")
                        stop()
                        return@post
                    }
                    println("Received benchmark result for: ${result.name}")

                    withContext(Dispatchers.IO) {
                        if (Config.saveStatsToJSON) {
                            saveJson(result.name, result.stats)
                        }

                        if (Config.saveStatsToCSV) {
                            // TODO: for CSV, we would need to convert JSON to the values
                            println("CSV results are not yet supported for the browser.")
                        }
                    }

                    call.respond(HttpStatusCode.OK, "Benchmark result saved")
                }