Add gradle plugin and fix authenticator

This commit is contained in:
2026-01-17 23:23:46 +08:00
parent 94a486a505
commit 546977fe86
40 files changed
+266 -86

No files matched your search

+3 -2
View File
@@ -2,5 +2,6 @@
.kotlin/
build/
.gradle/
/core/.dev.vars
/core/wrangler.toml
/worker-core/.dev.vars
/worker-core/wrangler.toml
/worker-plugin-test/wrangler.toml
+6 -5
View File
@@ -1,22 +1,23 @@
plugins {
kotlin("jvm") version "2.2.21" apply false
kotlin("multiplatform") version "2.2.21" apply false
kotlin("plugin.serialization") version "2.2.21" apply false
id("maven-publish")
}
val libVersion: String by extra
allprojects {
group = "cn.rtast.kotlin-cfworker"
version = "1.0.2"
group = "kotlin-cloudflare-worker"
version = libVersion
repositories {
mavenCentral()
maven("https://repo.maven.rtast.cn/releases")
}
}
subprojects {
apply(plugin = "org.jetbrains.kotlin.multiplatform")
apply(plugin = "maven-publish")
publishing {
-67
View File
@@ -1,67 +0,0 @@
kotlin {
explicitApi()
js(IR) { nodejs { binaries.executable() } }
sourceSets {
jsMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}
commonTest.dependencies {
implementation(kotlin("test"))
}
}
}
val wranglerRunDir: Provider<Directory> = layout.buildDirectory.dir("wrangler-run")
tasks.register<Copy>("prepareWranglerRun") {
group = "wrangler"
dependsOn("compileDevelopmentExecutableKotlinJs")
val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/developmentExecutable/kotlin")
from(buildOutputDir)
into(wranglerRunDir)
}
val wranglerDev by tasks.registering(Exec::class) {
group = "wrangler"
workingDir = layout.buildDirectory.dir("wrangler-run").get().asFile.apply { mkdirs() }
doFirst {
val sourceDir = project.layout.projectDirectory
mapOf(
sourceDir.file("wrangler.toml").asFile to File(workingDir, "wrangler.toml"),
sourceDir.file(".dev.vars").asFile to File(workingDir, ".dev.vars"),
).forEach { (s, d) -> s.copyTo(d, overwrite = true) }
}
commandLine(
if (System.getProperty("os.name").lowercase().contains("windows")) listOf(
"cmd", "/c", "wrangler dev --port 7071"
)
else listOf("sh", "-c", "wrangler dev --port 7071")
)
standardInput = System.`in`
isIgnoreExitValue = false
}
val wranglerDeployDir: Provider<Directory> = layout.buildDirectory.dir("wrangler-deploy")
.apply { get().asFile.deleteRecursively() }
val prepareProductionDeploy by tasks.registering(Copy::class) {
group = "wrangler"
dependsOn("compileProductionExecutableKotlinJs")
val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/productionExecutable/kotlin")
from(buildOutputDir) { exclude("*.map") }
into(wranglerDeployDir)
from(layout.projectDirectory.file("wrangler.toml"))
into(wranglerDeployDir)
}
val wranglerDeploy by tasks.registering(Exec::class) {
group = "wrangler"
dependsOn(prepareProductionDeploy)
workingDir = layout.buildDirectory.dir("wrangler-deploy").get().asFile.apply { mkdirs() }
commandLine(
if (System.getProperty("os.name").lowercase().contains("windows")) listOf("cmd", "/c", "wrangler deploy")
else listOf("sh", "-c", "wrangler deploy")
)
standardInput = System.`in`
}
+1
View File
@@ -1 +1,2 @@
kotlin.code.style=official
libVersion=1.0.4
-5
View File
@@ -1,5 +0,0 @@
kotlin {
js(IR) {
nodejs { binaries.executable() }
}
}
+22 -2
View File
@@ -1,3 +1,23 @@
include(":core")
include(":serialization")
@file:Suppress("UnstableApiUsage")
include(":worker-core")
include(":worker-serialization")
include(":worker-gradle-plugin")
pluginManagement {
repositories {
mavenCentral()
mavenLocal()
maven("https://repo.maven.rtast.cn/releases")
}
}
dependencyResolutionManagement {
repositories {
mavenCentral()
mavenLocal()
maven("https://repo.maven.rtast.cn/releases")
}
}
rootProject.name = "kotlin-cloudflare-worker"
+75
View File
@@ -0,0 +1,75 @@
plugins {
kotlin("multiplatform")
id("kotlin-cloudflare-worker") version "1.0.4"
}
kotlin {
explicitApi()
js(IR) { nodejs { binaries.executable() } }
sourceSets {
jsMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
}
commonTest.dependencies {
implementation(kotlin("test"))
}
}
}
wrangler {
wranglerFile = file("wrangler.toml")
}
//val wranglerRunDir: Provider<Directory> = layout.buildDirectory.dir("wrangler-run")
//tasks.register<Copy>("prepareWranglerRun") {
// group = "wrangler"
// dependsOn("compileDevelopmentExecutableKotlinJs")
// val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/developmentExecutable/kotlin")
// from(buildOutputDir)
// into(wranglerRunDir)
//}
//
//val wranglerDev by tasks.registering(Exec::class) {
// group = "wrangler"
// workingDir = layout.buildDirectory.dir("wrangler-run").get().asFile.apply { mkdirs() }
// doFirst {
// val sourceDir = project.layout.projectDirectory
// mapOf(
// sourceDir.file("wrangler.toml").asFile to File(workingDir, "wrangler.toml"),
// sourceDir.file(".dev.vars").asFile to File(workingDir, ".dev.vars"),
// ).forEach { (s, d) -> s.copyTo(d, overwrite = true) }
// }
// commandLine(
// if (System.getProperty("os.name").lowercase().contains("windows")) listOf(
// "cmd", "/c", "wrangler dev --port 7071"
// )
// else listOf("sh", "-c", "wrangler dev --port 7071")
// )
// standardInput = System.`in`
// isIgnoreExitValue = false
//}
//
//val wranglerDeployDir: Provider<Directory> = layout.buildDirectory.dir("wrangler-deploy")
// .apply { get().asFile.deleteRecursively() }
//val prepareProductionDeploy by tasks.registering(Copy::class) {
// group = "wrangler"
// dependsOn("compileProductionExecutableKotlinJs")
// val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/productionExecutable/kotlin")
// from(buildOutputDir) { exclude("*.map") }
// into(wranglerDeployDir)
// from(layout.projectDirectory.file("wrangler.toml"))
// into(wranglerDeployDir)
//}
//
//val wranglerDeploy by tasks.registering(Exec::class) {
// group = "wrangler"
// dependsOn(prepareProductionDeploy)
// workingDir = layout.buildDirectory.dir("wrangler-deploy").get().asFile.apply { mkdirs() }
// commandLine(
// if (System.getProperty("os.name").lowercase().contains("windows")) listOf("cmd", "/c", "wrangler deploy")
// else listOf("sh", "-c", "wrangler deploy")
// )
// standardInput = System.`in`
//}
@@ -8,6 +8,6 @@ import org.w3c.fetch.Request
* An interface for authenticating
* It's sealed
*/
public sealed interface Authenticator<in C : HttpCredential> {
public suspend fun authenticate(request: Request, credential: C?): AuthResult
public sealed interface Authenticator<out C : HttpCredential> {
public suspend fun authenticate(request: Request, credential: @UnsafeVariance C?): AuthResult
}
@@ -13,6 +13,9 @@
package cn.rtast.cfworker
import cn.rtast.cfworker.auth.AuthResult
import cn.rtast.cfworker.auth.provider.BearerAuthenticator
import cn.rtast.cfworker.client.Url
import cn.rtast.cfworker.response.respondText
import cn.rtast.cfworker.route.route
import cn.rtast.cfworker.websocket.readText
@@ -50,6 +53,13 @@ public fun handleRequest(request: Request): Promise<Response> = GlobalScope.prom
onClose {
}
}
route("/protected", setOf(HttpMethod.GET), BearerAuthenticator { request, credential ->
val name = request.Url.searchParams.get("name")
return@BearerAuthenticator if (name == "admin") AuthResult.OK else AuthResult.UNAUTHORIZED
}) {
respondText("Success")
}
}
return@promise server.handle(request)
}
@@ -28,7 +28,7 @@ import org.w3c.files.Blob
public class WebsocketEventHandler(public val request: Request) {
private var onMessageBlock: (suspend (MessageEvent) -> Unit)? = null
private var onCloseBlock: (suspend (CloseEvent) -> Unit?)? = null
private var onOpenBlock: (suspend (Event) -> Unit)? = null
private var onOpenBlock: (suspend () -> Unit)? = null
private var onErrorBlock: (suspend (Event) -> Unit)? = null
private var requireUpgradeHeaderBlock: (suspend (Request) -> Response)? =
{ Response("Expected Upgrade: websocket", ResponseInit(426)) }
@@ -46,7 +46,7 @@ public class WebsocketEventHandler(public val request: Request) {
onCloseBlock = block
}
public fun onOpen(block: suspend (Event) -> Unit) {
public fun onOpen(block: suspend () -> Unit) {
onOpenBlock = block
}
@@ -66,9 +66,9 @@ public class WebsocketEventHandler(public val request: Request) {
val server = pair[1]
server.accept()
clients.add(server)
GlobalScope.promise { onOpenBlock?.invoke() }
server.addEventListener("message", { e: MessageEvent -> GlobalScope.promise { onMessageBlock?.invoke(e) } })
server.addEventListener("error", { e: Event -> GlobalScope.promise { onErrorBlock?.invoke(e) } })
server.addEventListener("open", { e: Event -> GlobalScope.promise { onErrorBlock?.invoke(e) } })
server.addEventListener("close", { e: CloseEvent ->
GlobalScope.promise {
onCloseBlock?.invoke(e)
File renamed without changes.
+22
View File
@@ -0,0 +1,22 @@
plugins {
kotlin("jvm")
id("java-gradle-plugin")
}
gradlePlugin {
website = "https://github.com/RTAkland/kotlin-cloudflare-worker"
vcsUrl = "https://github.com/RTAkland/kotlin-cloudflare-worker.git"
plugins {
create("kotlin-cloudflare-worker") {
id = "kotlin-cloudflare-worker"
displayName = "kotlin cloudflare worker"
description = "Kotlin cloudflare worker gradle plugin"
tags = listOf("tool", "tasks")
implementationClass = "cn.rtast.cfworker.plugin.KotlinCloudflareWorkerPlugin"
}
}
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.21")
}
@@ -0,0 +1,75 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/1/17
*/
package cn.rtast.cfworker.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Exec
import java.io.File
class KotlinCloudflareWorkerPlugin : Plugin<Project> {
override fun apply(target: Project) {
val extension = target.extensions.create("wrangler", WorkerExtension::class.java)
val layout = target.layout
val wranglerRunDir = layout.buildDirectory.dir("wrangler-run")
target.tasks.register("prepareWranglerRun", Copy::class.java) {
it.group = "wrangler"
it.dependsOn("compileDevelopmentExecutableKotlinJs")
val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/developmentExecutable/kotlin")
it.from(buildOutputDir)
it.into(wranglerRunDir)
}
target.tasks.register("wranglerDev", Exec::class.java) { exec ->
exec.group = "wrangler"
exec.workingDir = layout.buildDirectory.dir("wrangler-run").get().asFile.apply { mkdirs() }
exec.doFirst {
val sourceDir = target.layout.projectDirectory
mutableMapOf(extension.wranglerFile.get() to File(exec.workingDir, "wrangler.toml")).apply {
val envFile = sourceDir.file(".dev.vars").asFile
if (envFile.exists()) this[envFile] = File(exec.workingDir, ".dev.vars")
}.forEach { (s, d) -> s.copyTo(d, overwrite = true) }
}
exec.commandLine(
if (System.getProperty("os.name").lowercase().contains("windows")) listOf(
"cmd", "/c", "wrangler dev --port ${extension.port.get()}"
)
else listOf("sh", "-c", "wrangler dev --port ${extension.port.get()}")
)
exec.standardInput = System.`in`
exec.isIgnoreExitValue = false
}
val wranglerDeployDir = layout.buildDirectory.dir("wrangler-deploy")
.apply { get().asFile.deleteRecursively() }
target.tasks.register("prepareProductionDeploy", Copy::class.java) { copy ->
copy.group = "wrangler"
copy.dependsOn("compileProductionExecutableKotlinJs")
val buildOutputDir = layout.buildDirectory.dir("compileSync/js/main/productionExecutable/kotlin")
copy.from(buildOutputDir) { it.exclude("*.map") }
copy.into(wranglerDeployDir)
copy.from(layout.projectDirectory.file("wrangler.toml"))
copy.into(wranglerDeployDir)
}
target.tasks.register("wranglerDeploy", Exec::class.java) {
it.group = "wrangler"
it.dependsOn("prepareProductionDeploy")
it.workingDir = layout.buildDirectory.dir("wrangler-deploy").get().asFile.apply { mkdirs() }
it.commandLine(
if (System.getProperty("os.name").lowercase().contains("windows")) listOf(
"cmd",
"/c",
"wrangler deploy"
)
else listOf("sh", "-c", "wrangler deploy")
)
it.standardInput = System.`in`
}
}
}
@@ -0,0 +1,12 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/1/17
*/
package cn.rtast.cfworker.plugin
internal enum class RunMode {
Development, Production
}
@@ -0,0 +1,25 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/1/17
*/
package cn.rtast.cfworker.plugin
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import java.io.File
abstract class WorkerExtension {
@get:Input
abstract val port: Property<Int>
@get:Input
abstract val wranglerFile: Property<File>
init {
wranglerFile.convention(File("wrangler.toml"))
port.convention(7071)
}
}
+10
View File
@@ -0,0 +1,10 @@
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
}
kotlin {
js(IR) {
nodejs { binaries.executable() }
}
}