From d62fa01d5727d39ee40061a80d0bba63c7e4a977 Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 00:44:18 +0800 Subject: [PATCH 1/8] Added dev info for agents, and make exact matches comes first. --- .github/workflows/gradle.yml | 34 ++- AGENTS.md | 223 ++++++++++++++++++ DEV_README.md | 91 ++++++- .../explode2/booster/bomb/BombPlugin.kt | 14 +- explode-all/build.gradle.kts | 2 +- explode-proxy/build.gradle.kts | 2 +- .../labyrinth/mongo/LabyrinthMongo.kt | 40 +++- 7 files changed, 387 insertions(+), 19 deletions(-) create mode 100644 AGENTS.md diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 2138fc8..42bf551 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -23,13 +23,35 @@ jobs: distribution: 'temurin' - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 - - name: Build with Gradle and Check JVM target version + - name: Build with Gradle + run: ./gradlew build -x test + - name: Verify bytecode version (JVM 17) run: | - ./gradlew build -x test 2>&1 | tee build.log - BUILD_EXIT_CODE=${PIPESTATUS[0]} - ./gradlew properties 2>&1 | grep -i "java\|jvm" - cat build.log || echo "Build log not available" - exit $BUILD_EXIT_CODE + JAVA17_MAJOR=61 + FAILED=0 + for jar in explode-all/build/libs/*.jar explode-proxy/build/libs/*.jar booster-plugins/*/build/libs/*.jar; do + [ -f "$jar" ] || continue + echo "Checking $jar" + FIRST_CLASS=$(unzip -Z1 "$jar" '*.class' | head -1) + if [ -n "$FIRST_CLASS" ]; then + TMPDIR=$(mktemp -d) + unzip -q -p "$jar" "$FIRST_CLASS" > "$TMPDIR/check.class" + MAJOR=$(od -An -j6 -N2 --endian=big -t u2 "$TMPDIR/check.class" | tr -d ' ') + echo " major version: $MAJOR" + rm -rf "$TMPDIR" + if [ "$MAJOR" != "$JAVA17_MAJOR" ]; then + echo " ERROR: expected $JAVA17_MAJOR, got $MAJOR" + FAILED=1 + fi + else + echo " WARNING: no .class files found" + fi + done + if [ "$FAILED" -ne 0 ]; then + echo "Bytecode version check failed!" + exit 1 + fi + echo "All checked JARs are JVM 17 bytecode (major version 61)." - name: Upload Artifacts uses: actions/upload-artifact@v4 with: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3803dfa --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,223 @@ +# AGENTS.md + +本文件面向 AI 编程助手,汇总 ExplodeExtreme(ExplodeX)项目的架构、构建、开发约定与运行方式。请在进行代码修改前阅读本文件。 + +## 项目概述 + +ExplodeExtreme(ExplodeX)是一个用于实现 Dynamite 游戏后端服务的项目。Dynamite 是 TunerGames 开发的音乐游戏,已于 2022 年中期因非技术原因停止运营;本项目旨在为仍然希望游玩该游戏的玩家提供私有/社区后端服务。 + +- **组织方式**:多模块 Kotlin(为主)+ Java Gradle 项目。 +- **根项目名称**:`explode2+`。 +- **Group**:`explode`。 +- **主版本**:`3.0.0`(根项目),`explode-all` 与 `explode-proxy` 当前版本为 `3.0.3`。 + +## 技术栈 + +- **构建工具**:Gradle 7.4.2(Wrapper)。 +- **Kotlin 版本**:1.7.20(根项目),`resource` 模块额外使用 Kotlinx Serialization 插件 1.8.20。 +- **JVM 目标**:17(`sourceCompatibility/targetCompatibility = 17`、`kotlinOptions.jvmTarget = "17"`、`options.release.set(17)`)。 +- **HTTP 服务端**:Ktor 2.1.2(Netty 引擎)。 +- **GraphQL**:`graphql-kotlin-server` 6.2.5、`graphql-java-extended-scalars` 20.0。 +- **依赖注入**:Koin 3.4.x。 +- **数据库**:MongoDB,通过 KMongo 4.7.1 访问。 +- **事件总线**:greenrobot EventBus 3.3.1。 +- **配置**:TConfig(`com.github.Taskeren:TConfig:1.2`)。 +- **日志**:SLF4J 2.0.5 + Log4j2 2.20.0。 +- **JSON**:Gson 2.10.1、Jackson 2.13.4。 +- **控制台命令**:brigadierX 1.2.2。 + +## 模块划分 + +| 模块 | 路径 | 作用 | +|------|------|------| +| `gateau` | `gateau/` | 业务对象/领域模型,仅包含接口(`GameUser`、`SongSet`、`SongChart`、`GameRecord` 等)。 | +| `labyrinth` | `labyrinth/` | 数据访问抽象层,定义 Repository 接口与 `LabyrinthProvider` SPI。 | +| `labyrinth-mongodb` | `labyrinth-mongodb/` | `LabyrinthProvider` 的 MongoDB 实现,基于 KMongo。 | +| `resource` | `resource/` | 资源存储抽象层,定义 `ResourceProvider`、`ResourceReceiver` 等,内置 `FileSystemProvider`。 | +| `booster` | `booster/` | 加载器核心(类似 Minecraft 服务端核心),负责插件加载、Ktor 启动、Koin 注入、GraphQL 与资源路由。 | +| `gatekeeper` | `gatekeeper/` | Booster 插件,提供交互式控制台命令(`exit`、`labyrinth`、用户相关命令、示例生成器等)。 | +| `explode-all` | `explode-all/` | 完整服务端可执行产物,Shadow JAR 打包 booster + resource + labyrinth + labyrinth-mongodb + gatekeeper。 | +| `explode-proxy` | `explode-proxy/` | 实验性代理服务器,将客户端 GraphQL 与资源请求转发到远程 Explode 后端。 | +| `maintain` | `booster-plugins/maintain/` | 示例/玩笑插件,在根路径 `/` 显示维护页面。 | +| `url-redirect-resource` | `booster-plugins/url-redirect-resource/` | 资源插件,通过配置的重定向 URL 响应资源请求。 | +| `aliyun-oss-resource` | `booster-plugins/aliyun-oss-resource/` | 资源插件,使用阿里云 OSS 存储并返回签名 URL,支持上传。 | +| `dynamite-cli` | `devtools/dynamite-cli/` | 独立 GraphQL 客户端 CLI,用于手动测试。 | + +## 代码组织 + +- **根包名**:`explode2.*`。 +- `gateau`:`explode2.gateau.*` +- `labyrinth` 抽象层:`explode2.labyrinth.*` +- MongoDB 实现:`explode2.labyrinth.mongo.*` +- `booster` 核心:`explode2.booster.*` +- GraphQL 定义:`explode2.booster.graphql.definition.*` +- REST(Bomb)API:`explode2.booster.bomb.*` +- 资源相关:`explode2.booster.resource.*` +- 控制台插件:`explode2.booster.gatekeeper.*` +- 插件类:`explode2.booster..*` + +## 构建与运行 + +### 常用 Gradle 命令 + +```bash +# 构建全部模块(CI 使用,跳过测试) +./gradlew build -x test + +# 运行测试 +./gradlew test + +# 运行完整服务端(工作目录会自动切换到 run/) +./gradlew :explode-all:run + +# 构建并收集产物到 build/gather-builds// +./gradlew build +``` + +### 产物说明 + +构建完成后主要产物位于各模块 `build/libs/` 下,`gatherArtifact` 任务会将它们收集到 `build/gather-builds//`。 + +- `explode-all--all.jar`:完整服务端 Fat JAR,部署时使用。 +- `explode-all-.jar`:非 Shadow JAR。 +- `explode-proxy--all.jar`:代理服务端 Fat JAR。 +- `booster-plugins/*/.jar`:插件 JAR。 + +### 运行服务端 + +```bash +java -cp explode-all--all.jar explode2.booster.BoosterMainKt +``` + +- 插件 JAR 需要放在 `./plugins/` 目录下(与主 JAR 同目录)。 +- `explode-all` 的 `application` 插件默认将 `gradlew run` 的工作目录设为 `run/`。 + +### 运行代理 + +```bash +java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt +``` + +代理同样使用 `explode2.booster.BoosterMainKt` 入口,但类路径上加载的是代理版 `MazeProvider` 与 `ResourceProvider`。 + +## 配置与环境变量 + +### 环境变量 + +- `DB_URL`:MongoDB 连接字符串(优先级高于 `labyrinth.cfg` 中的 `connection-string`)。 +- `DB_NAME`:MongoDB 数据库名(优先级高于 `labyrinth.cfg` 中的 `database-name`)。 + +### 系统属性 + +- `ex.addr`:覆盖监听地址。 +- `ex.port`:覆盖监听端口。 + +### 运行时生成的配置文件 + +- `explode.cfg`:监听地址/端口(`general.addr`、`general.port`)。 +- `labyrinth.cfg`:MongoDB 连接字符串与数据库名。 +- `basic-maze.cfg`:提交过期时间、排行榜刷新间隔等。 +- `bomb-api.cfg`:Bomb API 路由前缀、Superstar 后门开关等。 +- 插件自有配置:如 `redirect.resource.cfg`、`aliyun-oss.resource.cfg`、`proxy_maze.cfg` 等。 + +## 插件系统 + +项目使用 **Java `ServiceLoader` + 运行时追加 classpath** 的方式加载插件。 + +### 开发一个 Booster 插件 + +1. 在 `booster-plugins/` 下新建模块,或在 `settings.gradle.kts` 中通过 `includePlugin("name")` 注册。 +2. 模块依赖 `project(":booster")`。 +3. 创建一个实现 `explode2.booster.BoosterPlugin` 的类,并提供无参构造函数。 +4. 在 `src/main/resources/META-INF/services/explode2.booster.BoosterPlugin` 中写入该类的全限定名。 +5. 插件生命周期方法:`onPreInit()`、`onInit()`、`onPostInit()`。 +6. 插件默认是 Koin 组件,可通过依赖注入获取 Repository;可通过 `subscribeEvents()` 注册 EventBus 监听器。 + +### 其他 SPI + +除 `BoosterPlugin` 外,以下接口也通过 `META-INF/services` 注册: + +- `explode2.labyrinth.LabyrinthProvider`:数据后端(MongoDB 实现、代理 no-op 实现)。 +- `explode2.booster.resource.ResourceProvider`:资源后端(文件系统、URL 重定向、阿里云 OSS、代理)。 +- `explode2.booster.graphql.MazeProvider`:GraphQL Query/Mutation 提供者(默认 `BasicMaze`、代理 `ProxyMaze`)。 + +## 运行时架构 + +### 启动流程(`explode2.booster.BoosterMainKt`) + +1. 初始化 `Explode` 单例(配置、EventBus、Koin 模块)。 +2. 扫描 `./plugins/*.jar` 并通过 `ClassLoaderUtils` 追加到 classpath。 +3. 通过 `ServiceLoader` 实例化所有 `BoosterPlugin`。 +4. 校验至少存在一个插件,否则退出。 +5. 依次派发 `onPreInit()`、`onInit()`、`onPostInit()`。 +6. 保存所有配置。 +7. 在独立线程中启动 Netty/Ktor,默认监听 `0.0.0.0:10443`。 + +### HTTP API + +同时暴露两套 API: + +1. **GraphQL API**:默认路径 `/graphql`,另有 `/sdl`(打印 Schema)、`/playground`。 + - 认证通过请求头 `x-soudayo` 传递 token,解析为当前 `GameUser`。 + - Query 包括 `self`、`set`、`userByUsername`、`playRank`、`assessmentGroup` 等。 + - Mutation 包括 `loginUser`、`registerUser`、`exchangeSet`、`submitBeforePlay`、`submitAfterPlay` 等。 + +2. **Bomb REST API**:默认根路径 `/bomb/v2`(可在 `bomb-api.cfg` 中配置模板 `bomb/v{version}`)。 + - 用户相关:`/user/me`、`/user/{id}`、`/user/{id}/best`、`/user/{id}/last`、修改用户名/密码、注册、搜索等。 + - 曲目/谱面:`/set/{id}`、`/chart/{id}`。 + - 上传:`/upload`(需要 `bomb.upload` 权限)。 + - 迁移:`/migrate`。 + +3. **资源服务**:`/download/...` 提供音乐、预览、封面、谱面 XML、商店封面、头像等资源;当 `ResourceProvider` 为 `RedirectResourceProvider` 时返回重定向,为 `ByteArrayResourceProvider` 时直接返回内容。支持 `POST` 上传(若 provider 实现 `ResourceReceiver`)。 + +## 数据层 + +- **gateau**:纯领域接口,无实现。 +- **labyrinth**:Repository 接口与 `LabyrinthProvider`。 +- **labyrinth-mongodb**: + - `LabyrinthMongoProvider` 通过 `DB_URL`/`DB_NAME` 或 `labyrinth.cfg` 连接 MongoDB。 + - `MongoManager` 实现所有 Repository 接口,集合包括 `Sets`、`Charts`、`Users`、`GameRecords`、`AssessRecords`、`AssessInfo`。 + - 使用委托模式(`SongSetDelegate`、`SongChartDelegate`、`GameUserDelegate` 等)将 `gateau` 接口与 MongoDB 文档桥接,修改后写回数据库。 + - 排行榜使用 MongoDB 聚合管道(`setWindowFields`、`rank`)计算。 + +## 测试 + +项目当前测试覆盖较少: + +- `booster/src/test/kotlin/TestColorOutput.kt`:JUnit 5 日志颜色冒烟测试。 +- `devtools/dynamite-cli/src/test/kotlin/TestGraphqlRequests.kt`:`kotlin.test` 集成测试,默认标记为 `@Ignore`,目标为 `localhost:10443/graphql`。 +- CI 使用 `./gradlew build -x test`,因此构建不会阻塞于测试。 + +## 代码风格 + +参考 `CONTRIBUTING.md`、`DEV_README.md` 与 `.editorconfig`。 + +- 缩进使用 **Tab**(`indent_style = tab`),而非空格。 +- Kotlin 基本遵循旧版 IntelliJ IDEA Kotlin codestyle,例外: + - 枚举与常量命名允许 `UpperCamelCase` 或 `UPPER_SNAKE_CASE`(正则 `[A-Z][_a-zA-Z\d]*`)。 + - 控制关键字与左括号之间**不加空格**:`if(true)`、`for(...)`、`while(...)`、`catch(...)`、`when(...)`。 + - 注解与被注解代码**换行**。 + - 限制 Top Level Function 的使用范围。 +- Java:IntelliJ 默认规范 + Tab 缩进 + 控制关键字前不加空格。 +- Markdown:尽量遵循 Google Markdown Style Guide。 +- 编码:UTF-8。 + +## 部署与 CI/CD + +- GitHub Actions 配置:`.github/workflows/gradle.yml`。 +- 触发条件:`v3` 分支的 push 与 pull_request。 +- 运行环境:Ubuntu Latest、JDK 17 Temurin、Gradle setup action v6。 +- 构建命令:`./gradlew build -x test`。 +- 上传产物:`explode-all/build/libs/`、`explode-proxy/build/libs/`、`booster-plugins/*/build/libs/`。 + +## 安全与敏感信息 + +- MongoDB 连接字符串等敏感信息通过环境变量或本地配置文件传入,不应提交到仓库。 +- `explode-proxy` 会将远程登录凭据缓存在运行目录的 `.proxy_cache` 文件中,该文件**不得上传或共享**;重置代理服务器时应删除它。 +- Bomb API 存在 `Superstar` 后门配置:启用后允许一个随机 UUID 账户以任意用户身份登录,仅应在受控测试环境使用。 + +## 其他注意事项 + +- 项目声明了一个 Git 子模块 `TunerGamesEncryption`(指向 `git@github.com:Taskeren/Explode-Crypto.git`),但在当前工作树中可能未检出(路径 `TunerGamesEncryption` 不存在)。 +- `src/main/kotlin/explode2/tests/Main.kt` 是开发用的临时/草稿代码,不是正式测试。 +- 新开发优先参考现有模块(如 `gatekeeper` 或 `booster-plugins/maintain`)的目录结构与 `META-INF/services` 注册方式。 diff --git a/DEV_README.md b/DEV_README.md index 58bd76a..a733f5d 100644 --- a/DEV_README.md +++ b/DEV_README.md @@ -6,13 +6,14 @@ `booster` 是加载器模块,可以类比与 Minecraft 的服务器核心,以 `booster-` 开头的模块就是在加载器下面跑的具体内容,类似于服务器中的插件。 -在插件模块中需要有一个类继承 `explode2.booster.BoosterPlugin`,且有无参构造函数,然后在 `META-INF/services` 中添加文件 `explode2.booster.BoosterPlugin`,内容为该类的位置。 +在插件模块中需要有一个类继承 `explode2.booster.BoosterPlugin`,且有无参构造函数, +然后在 `META-INF/services` 中添加文件 `explode2.booster.BoosterPlugin`,内容为该类的位置。 ### Gateau Business Objects 原文应该是 `gâteau`,内容是业务对象。 -### 数据提供 Labyrinth +### 数据提供 Labyrinth ## Artifacts @@ -119,3 +120,89 @@ to load all plugin JARs. ```json {"success":true,"data":{"id":"QLi2mcC76xK9aZ8bwFDyUBCE","difficulty_class":5,"difficulty_value":15}} ``` + +## 构建与运行 + +### 常用 Gradle 命令 + +```bash +# 构建全部模块(CI 使用,跳过测试) +./gradlew build -x test + +# 运行测试 +./gradlew test + +# 运行完整服务端(工作目录会自动切换到 run/) +./gradlew :explode-all:run + +# 构建并收集产物到 build/gather-builds// +./gradlew build +``` + +### 运行服务端 + +```bash +java -cp explode-all--all.jar explode2.booster.BoosterMainKt +``` + +插件 JAR 需要放在 `./plugins/` 目录下(与主 JAR 同目录)。 +`explode-all` 的 `application` 插件默认将 `gradlew run` 的工作目录设为 `run/`。 + +### 运行代理 + +```bash +java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt +``` + +代理同样使用 `explode2.booster.BoosterMainKt` 入口,但类路径上加载的是代理版 `MazeProvider` 与 `ResourceProvider`。 + +## 配置与环境变量 + +### 环境变量 + +- `DB_URL`:MongoDB 连接字符串(优先级高于 `labyrinth.cfg` 中的 `connection-string`)。 +- `DB_NAME`:MongoDB 数据库名(优先级高于 `labyrinth.cfg` 中的 `database-name`)。 + +### 系统属性 + +- `ex.addr`:覆盖监听地址。 +- `ex.port`:覆盖监听端口。 + +### 运行时生成的配置文件 + +- `explode.cfg`:监听地址/端口(`general.addr`、`general.port`)。 +- `labyrinth.cfg`:MongoDB 连接字符串与数据库名。 +- `basic-maze.cfg`:提交过期时间、排行榜刷新间隔等。 +- `bomb-api.cfg`:Bomb API 路由前缀、Superstar 后门开关等。 +- 插件自有配置:如 `redirect.resource.cfg`、`aliyun-oss.resource.cfg`、`proxy_maze.cfg` 等。 + +## 代码风格 + +参考 `CONTRIBUTING.md` 与 `.editorconfig`。 + +- 缩进使用 **Tab**(`indent_style = tab`),而非空格。 +- Kotlin 基本遵循旧版 IntelliJ IDEA Kotlin codestyle,例外: + - 枚举与常量命名允许 `UpperCamelCase` 或 `UPPER_SNAKE_CASE` + (正则 `[A-Z][_a-zA-Z\d]*`)。 + - 控制关键字与左括号之间**不加空格**: + `if(true)`、`for(...)`、`while(...)`、`catch(...)`、`when(...)`。 + - 注解与被注解代码**换行**。 + - 限制 Top Level Function 的使用范围。 +- Java:IntelliJ 默认规范 + Tab 缩进 + 控制关键字前不加空格。 +- Markdown:尽量遵循 Google Markdown Style Guide。 +- 编码:UTF-8。 + +## 安全与敏感信息 + +- MongoDB 连接字符串等敏感信息通过环境变量或本地配置文件传入,不应提交到仓库。 +- `explode-proxy` 会将远程登录凭据缓存在运行目录的 `.proxy_cache` 文件中,该文件**不得上传或共享**;重置代理服务器时应删除它。 +- Bomb API 存在 `Superstar` 后门配置:启用后允许一个随机 UUID 账户以任意用户身份登录,仅应在受控测试环境使用。 + +## 其他注意事项 + +- 项目声明了一个 Git 子模块 `TunerGamesEncryption` + (指向 `git@github.com:Taskeren/Explode-Crypto.git`), + 但在当前工作树中可能未检出(路径 `TunerGamesEncryption` 不存在)。 +- `src/main/kotlin/explode2/tests/Main.kt` 是开发用的临时/草稿代码,不是正式测试。 +- 新开发优先参考现有模块(如 `gatekeeper` 或 `booster-plugins/maintain`) + 的目录结构与 `META-INF/services` 注册方式。 diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index f7f5bb8..f3ae0ab 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -56,7 +56,8 @@ class BombPlugin : BoosterPlugin { init { subscribeEvents() - saveConfig() + // actually generates a blank .cfg file. + saveConfig() if(useSuperstar) { logger.info(superstarMarker, "Superstar Enabled") @@ -165,10 +166,13 @@ private val bombModule: RouteConfigure = { logger.debug(configureMarker, "Installing DefaultModule") - // [/] 用来测试的接口 - get { - bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) - } + // [/] or [] 用来测试的接口(欢迎语) + route("") { + get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } + } + route("/") { + get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } + } // 用户接口模块 logger.debug(configureMarker, "Installing UserModule") diff --git a/explode-all/build.gradle.kts b/explode-all/build.gradle.kts index f0930bb..80f9756 100644 --- a/explode-all/build.gradle.kts +++ b/explode-all/build.gradle.kts @@ -6,7 +6,7 @@ plugins { // It's explode v3 now group = "explode" -version = "3.0.3" +version = "3.0.4" repositories { mavenCentral() diff --git a/explode-proxy/build.gradle.kts b/explode-proxy/build.gradle.kts index c69fd46..968bb1a 100644 --- a/explode-proxy/build.gradle.kts +++ b/explode-proxy/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "explode" -version = "3.0.3" +version = "3.0.4" repositories { mavenCentral() diff --git a/labyrinth-mongodb/src/main/kotlin/explode2/labyrinth/mongo/LabyrinthMongo.kt b/labyrinth-mongodb/src/main/kotlin/explode2/labyrinth/mongo/LabyrinthMongo.kt index 3d3e245..334349a 100644 --- a/labyrinth-mongodb/src/main/kotlin/explode2/labyrinth/mongo/LabyrinthMongo.kt +++ b/labyrinth-mongodb/src/main/kotlin/explode2/labyrinth/mongo/LabyrinthMongo.kt @@ -97,8 +97,10 @@ class MongoManager(private val provider: LabyrinthMongoBuilder = LabyrinthMongoB class SongSetWithCharts(val charts: List) class SongSetWithPlayCount(val playCount: Int) + class SongSetExactMatch(val exactMatch: Boolean) val pipeline: MutableList = mutableListOf() + var isNameSearch = false if(!matchingName.isNullOrBlank()) { val proc = StringProcessor(matchingName) @@ -197,6 +199,7 @@ class MongoManager(private val provider: LabyrinthMongoBuilder = LabyrinthMongoB // 默认模糊查询名字(先尝试正则,编译失败则降级为字面量匹配) else -> { + isNameSearch = true val patternString = kotlin.runCatching { Regex(matchingName) // 验证是否为合法正则 matchingName // 合法则使用原始字符串 @@ -242,17 +245,39 @@ class MongoManager(private val provider: LabyrinthMongoBuilder = LabyrinthMongoB } } + // 为名称搜索添加精确匹配字段,以便优先返回精确匹配的结果 + if(isNameSearch) { + pipeline += addFields(Field( + "exactMatch", + MongoOperator.eq.from(listOf("\$musicName", matchingName)) + )) + } + // 排序顺序 when(sortBy) { null, // Descending by time SearchSort.DESCENDING_BY_PUBLISH_TIME -> { - pipeline += sort(descending(MongoSongSet::publishTime, MongoSongSet::musicName, MongoSongSet::id)) + pipeline += sort( + descending( + SongSetExactMatch::exactMatch, + MongoSongSet::publishTime, + MongoSongSet::musicName, + MongoSongSet::id + ) + ) } // Ascending by time (Updated 2026.6.2) SearchSort.ASCENDING_BY_PUBLISH_TIME -> { - pipeline += sort(ascending(MongoSongSet::publishTime, MongoSongSet::musicName, MongoSongSet::id)) - } + pipeline += sort( + descending( + SongSetExactMatch::exactMatch, + MongoSongSet::publishTime, + MongoSongSet::musicName, + MongoSongSet::id + ) + ) + } // FIXME: 修复性能问题 SearchSort.DESCENDING_BY_PLAY_COUNT -> { // 添加游玩次数查询 @@ -261,7 +286,14 @@ class MongoManager(private val provider: LabyrinthMongoBuilder = LabyrinthMongoB "playCount", MongoOperator.size.from("\$playRecords") )) - pipeline += sort(descending(SongSetWithPlayCount::playCount, MongoSongSet::musicName, MongoSongSet::id)) + pipeline += sort( + descending( + SongSetExactMatch::exactMatch, + SongSetWithPlayCount::playCount, + MongoSongSet::musicName, + MongoSongSet::id + ) + ) } } From e76930bf9e9b41f356d00265b336592f8fcd5fad Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 01:33:47 +0800 Subject: [PATCH 2/8] codacy requirements: <80 characters per line --- AGENTS.md | 163 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 53 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3803dfa..b585f7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,23 +1,30 @@ # AGENTS.md -本文件面向 AI 编程助手,汇总 ExplodeExtreme(ExplodeX)项目的架构、构建、开发约定与运行方式。请在进行代码修改前阅读本文件。 +本文件面向 AI 编程助手,汇总 ExplodeExtreme(ExplodeX)项目的架构、构建、 +开发约定与运行方式。请在进行代码修改前阅读本文件。 ## 项目概述 -ExplodeExtreme(ExplodeX)是一个用于实现 Dynamite 游戏后端服务的项目。Dynamite 是 TunerGames 开发的音乐游戏,已于 2022 年中期因非技术原因停止运营;本项目旨在为仍然希望游玩该游戏的玩家提供私有/社区后端服务。 +ExplodeExtreme(ExplodeX)是一个用于实现 Dynamite 游戏后端服务的项目。 +Dynamite 是 TunerGames 开发的音乐游戏,已于 2022 年中期因非技术原因停止运营; +本项目旨在为仍然希望游玩该游戏的玩家提供私有/社区后端服务。 - **组织方式**:多模块 Kotlin(为主)+ Java Gradle 项目。 - **根项目名称**:`explode2+`。 - **Group**:`explode`。 -- **主版本**:`3.0.0`(根项目),`explode-all` 与 `explode-proxy` 当前版本为 `3.0.3`。 +- **主版本**:`3.0.0`(根项目),`explode-all` 与 `explode-proxy` + 当前版本为 `3.0.4`。 ## 技术栈 - **构建工具**:Gradle 7.4.2(Wrapper)。 -- **Kotlin 版本**:1.7.20(根项目),`resource` 模块额外使用 Kotlinx Serialization 插件 1.8.20。 -- **JVM 目标**:17(`sourceCompatibility/targetCompatibility = 17`、`kotlinOptions.jvmTarget = "17"`、`options.release.set(17)`)。 +- **Kotlin 版本**:1.7.20(根项目),`resource` 模块额外使用 + Kotlinx Serialization 插件 1.8.20。 +- **JVM 目标**:17(`sourceCompatibility/targetCompatibility = 17`、 + `kotlinOptions.jvmTarget = "17"`、`options.release.set(17)`)。 - **HTTP 服务端**:Ktor 2.1.2(Netty 引擎)。 -- **GraphQL**:`graphql-kotlin-server` 6.2.5、`graphql-java-extended-scalars` 20.0。 +- **GraphQL**:`graphql-kotlin-server` 6.2.5、 + `graphql-java-extended-scalars` 20.0。 - **依赖注入**:Koin 3.4.x。 - **数据库**:MongoDB,通过 KMongo 4.7.1 访问。 - **事件总线**:greenrobot EventBus 3.3.1。 @@ -29,19 +36,31 @@ ExplodeExtreme(ExplodeX)是一个用于实现 Dynamite 游戏后端服务的 ## 模块划分 | 模块 | 路径 | 作用 | -|------|------|------| -| `gateau` | `gateau/` | 业务对象/领域模型,仅包含接口(`GameUser`、`SongSet`、`SongChart`、`GameRecord` 等)。 | -| `labyrinth` | `labyrinth/` | 数据访问抽象层,定义 Repository 接口与 `LabyrinthProvider` SPI。 | -| `labyrinth-mongodb` | `labyrinth-mongodb/` | `LabyrinthProvider` 的 MongoDB 实现,基于 KMongo。 | -| `resource` | `resource/` | 资源存储抽象层,定义 `ResourceProvider`、`ResourceReceiver` 等,内置 `FileSystemProvider`。 | -| `booster` | `booster/` | 加载器核心(类似 Minecraft 服务端核心),负责插件加载、Ktor 启动、Koin 注入、GraphQL 与资源路由。 | -| `gatekeeper` | `gatekeeper/` | Booster 插件,提供交互式控制台命令(`exit`、`labyrinth`、用户相关命令、示例生成器等)。 | -| `explode-all` | `explode-all/` | 完整服务端可执行产物,Shadow JAR 打包 booster + resource + labyrinth + labyrinth-mongodb + gatekeeper。 | -| `explode-proxy` | `explode-proxy/` | 实验性代理服务器,将客户端 GraphQL 与资源请求转发到远程 Explode 后端。 | -| `maintain` | `booster-plugins/maintain/` | 示例/玩笑插件,在根路径 `/` 显示维护页面。 | -| `url-redirect-resource` | `booster-plugins/url-redirect-resource/` | 资源插件,通过配置的重定向 URL 响应资源请求。 | -| `aliyun-oss-resource` | `booster-plugins/aliyun-oss-resource/` | 资源插件,使用阿里云 OSS 存储并返回签名 URL,支持上传。 | -| `dynamite-cli` | `devtools/dynamite-cli/` | 独立 GraphQL 客户端 CLI,用于手动测试。 | +| ------ | ------ | ------ | +| `gateau` | `gateau/` | 业务对象/领域模型,仅包含接口。 | +| `labyrinth` | `labyrinth/` | 数据访问抽象层,定义 Repository 与 SPI。 | +| `labyrinth-mongodb` | `labyrinth-mongodb/` | MongoDB 数据后端实现。 | +| `resource` | `resource/` | 资源存储抽象层,内置文件系统实现。 | +| `booster` | `booster/` | 加载器核心,负责插件、Ktor、GraphQL 等。 | +| `gatekeeper` | `gatekeeper/` | Booster 插件,提供控制台命令。 | +| `explode-all` | `explode-all/` | 完整服务端可执行 Fat JAR。 | +| `explode-proxy` | `explode-proxy/` | 实验性代理服务器。 | +| `maintain` | `booster-plugins/maintain/` | 示例插件,在根路径显示维护页面。 | +| `url-redirect-resource` | `booster-plugins/url-redirect-resource/` | 重定向资源。 | +| `aliyun-oss-resource` | `booster-plugins/aliyun-oss-resource/` | 阿里云 OSS 资源。 | +| `dynamite-cli` | `devtools/dynamite-cli/` | 独立 GraphQL 客户端 CLI。 | + +详细说明: + +- `gateau` 包含 `GameUser`、`SongSet`、`SongChart`、`GameRecord` 等接口。 +- `labyrinth` 的 SPI 为 `LabyrinthProvider`。 +- `resource` 定义 `ResourceProvider`、`ResourceReceiver` 等。 +- `booster` 负责插件加载、Ktor 启动、Koin 注入、GraphQL 与资源路由。 +- `gatekeeper` 提供 `exit`、`labyrinth`、用户相关命令、示例生成器等。 +- `explode-all` 通过 Shadow JAR 打包 booster、resource、labyrinth、 + labyrinth-mongodb、gatekeeper。 +- `explode-proxy` 将客户端 GraphQL 与资源请求转发到远程 Explode 后端。 +- `aliyun-oss-resource` 使用阿里云 OSS 存储并返回签名 URL,支持上传。 ## 代码组织 @@ -76,7 +95,8 @@ ExplodeExtreme(ExplodeX)是一个用于实现 Dynamite 游戏后端服务的 ### 产物说明 -构建完成后主要产物位于各模块 `build/libs/` 下,`gatherArtifact` 任务会将它们收集到 `build/gather-builds//`。 +构建完成后主要产物位于各模块 `build/libs/` 下,`gatherArtifact` 任务会将它们 +收集到 `build/gather-builds//`。 - `explode-all--all.jar`:完整服务端 Fat JAR,部署时使用。 - `explode-all-.jar`:非 Shadow JAR。 @@ -90,7 +110,8 @@ java -cp explode-all--all.jar explode2.booster.BoosterMainKt ``` - 插件 JAR 需要放在 `./plugins/` 目录下(与主 JAR 同目录)。 -- `explode-all` 的 `application` 插件默认将 `gradlew run` 的工作目录设为 `run/`。 +- `explode-all` 的 `application` 插件默认将 `gradlew run` 的 + 工作目录设为 `run/`。 ### 运行代理 @@ -98,14 +119,17 @@ java -cp explode-all--all.jar explode2.booster.BoosterMainKt java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt ``` -代理同样使用 `explode2.booster.BoosterMainKt` 入口,但类路径上加载的是代理版 `MazeProvider` 与 `ResourceProvider`。 +代理同样使用 `explode2.booster.BoosterMainKt` 入口,但类路径上加载的是 +代理版 `MazeProvider` 与 `ResourceProvider`。 ## 配置与环境变量 ### 环境变量 -- `DB_URL`:MongoDB 连接字符串(优先级高于 `labyrinth.cfg` 中的 `connection-string`)。 -- `DB_NAME`:MongoDB 数据库名(优先级高于 `labyrinth.cfg` 中的 `database-name`)。 +- `DB_URL`:MongoDB 连接字符串(优先级高于 `labyrinth.cfg` 中的 + `connection-string`)。 +- `DB_NAME`:MongoDB 数据库名(优先级高于 `labyrinth.cfg` 中的 + `database-name`)。 ### 系统属性 @@ -118,7 +142,8 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt - `labyrinth.cfg`:MongoDB 连接字符串与数据库名。 - `basic-maze.cfg`:提交过期时间、排行榜刷新间隔等。 - `bomb-api.cfg`:Bomb API 路由前缀、Superstar 后门开关等。 -- 插件自有配置:如 `redirect.resource.cfg`、`aliyun-oss.resource.cfg`、`proxy_maze.cfg` 等。 +- 插件自有配置:如 `redirect.resource.cfg`、 + `aliyun-oss.resource.cfg`、`proxy_maze.cfg` 等。 ## 插件系统 @@ -126,20 +151,27 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt ### 开发一个 Booster 插件 -1. 在 `booster-plugins/` 下新建模块,或在 `settings.gradle.kts` 中通过 `includePlugin("name")` 注册。 +1. 在 `booster-plugins/` 下新建模块,或在 `settings.gradle.kts` 中 + 通过 `includePlugin("name")` 注册。 2. 模块依赖 `project(":booster")`。 -3. 创建一个实现 `explode2.booster.BoosterPlugin` 的类,并提供无参构造函数。 -4. 在 `src/main/resources/META-INF/services/explode2.booster.BoosterPlugin` 中写入该类的全限定名。 +3. 创建一个实现 `explode2.booster.BoosterPlugin` 的类, + 并提供无参构造函数。 +4. 在 `src/main/resources/META-INF/services/explode2.booster.BoosterPlugin` + 中写入该类的全限定名。 5. 插件生命周期方法:`onPreInit()`、`onInit()`、`onPostInit()`。 -6. 插件默认是 Koin 组件,可通过依赖注入获取 Repository;可通过 `subscribeEvents()` 注册 EventBus 监听器。 +6. 插件默认是 Koin 组件,可通过依赖注入获取 Repository; + 可通过 `subscribeEvents()` 注册 EventBus 监听器。 ### 其他 SPI 除 `BoosterPlugin` 外,以下接口也通过 `META-INF/services` 注册: -- `explode2.labyrinth.LabyrinthProvider`:数据后端(MongoDB 实现、代理 no-op 实现)。 -- `explode2.booster.resource.ResourceProvider`:资源后端(文件系统、URL 重定向、阿里云 OSS、代理)。 -- `explode2.booster.graphql.MazeProvider`:GraphQL Query/Mutation 提供者(默认 `BasicMaze`、代理 `ProxyMaze`)。 +- `explode2.labyrinth.LabyrinthProvider`:数据后端 + (MongoDB 实现、代理 no-op 实现)。 +- `explode2.booster.resource.ResourceProvider`:资源后端 + (文件系统、URL 重定向、阿里云 OSS、代理)。 +- `explode2.booster.graphql.MazeProvider`:GraphQL Query/Mutation 提供者 + (默认 `BasicMaze`、代理 `ProxyMaze`)。 ## 运行时架构 @@ -157,27 +189,40 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt 同时暴露两套 API: -1. **GraphQL API**:默认路径 `/graphql`,另有 `/sdl`(打印 Schema)、`/playground`。 +1. **GraphQL API**:默认路径 `/graphql`,另有 `/sdl`(打印 Schema)、 + `/playground`。 - 认证通过请求头 `x-soudayo` 传递 token,解析为当前 `GameUser`。 - - Query 包括 `self`、`set`、`userByUsername`、`playRank`、`assessmentGroup` 等。 - - Mutation 包括 `loginUser`、`registerUser`、`exchangeSet`、`submitBeforePlay`、`submitAfterPlay` 等。 - -2. **Bomb REST API**:默认根路径 `/bomb/v2`(可在 `bomb-api.cfg` 中配置模板 `bomb/v{version}`)。 - - 用户相关:`/user/me`、`/user/{id}`、`/user/{id}/best`、`/user/{id}/last`、修改用户名/密码、注册、搜索等。 + - Query 包括 `self`、`set`、`userByUsername`、`playRank`、 + `assessmentGroup` 等。 + - Mutation 包括 `loginUser`、`registerUser`、`exchangeSet`、 + `submitBeforePlay`、`submitAfterPlay` 等。 + +2. **Bomb REST API**:默认根路径 `/bomb/v2`(可在 `bomb-api.cfg` 中 + 配置模板 `bomb/v{version}`)。 + - 用户相关:`/user/me`、`/user/{id}`、`/user/{id}/best`、 + `/user/{id}/last`、修改用户名/密码、注册、搜索等。 - 曲目/谱面:`/set/{id}`、`/chart/{id}`。 - 上传:`/upload`(需要 `bomb.upload` 权限)。 - 迁移:`/migrate`。 -3. **资源服务**:`/download/...` 提供音乐、预览、封面、谱面 XML、商店封面、头像等资源;当 `ResourceProvider` 为 `RedirectResourceProvider` 时返回重定向,为 `ByteArrayResourceProvider` 时直接返回内容。支持 `POST` 上传(若 provider 实现 `ResourceReceiver`)。 +3. **资源服务**:`/download/...` 提供音乐、预览、封面、谱面 XML、 + 商店封面、头像等资源;当 `ResourceProvider` 为 + `RedirectResourceProvider` 时返回重定向,为 + `ByteArrayResourceProvider` 时直接返回内容。支持 `POST` 上传 + (若 provider 实现 `ResourceReceiver`)。 ## 数据层 - **gateau**:纯领域接口,无实现。 - **labyrinth**:Repository 接口与 `LabyrinthProvider`。 - **labyrinth-mongodb**: - - `LabyrinthMongoProvider` 通过 `DB_URL`/`DB_NAME` 或 `labyrinth.cfg` 连接 MongoDB。 - - `MongoManager` 实现所有 Repository 接口,集合包括 `Sets`、`Charts`、`Users`、`GameRecords`、`AssessRecords`、`AssessInfo`。 - - 使用委托模式(`SongSetDelegate`、`SongChartDelegate`、`GameUserDelegate` 等)将 `gateau` 接口与 MongoDB 文档桥接,修改后写回数据库。 + - `LabyrinthMongoProvider` 通过 `DB_URL`/`DB_NAME` 或 + `labyrinth.cfg` 连接 MongoDB。 + - `MongoManager` 实现所有 Repository 接口,集合包括 `Sets`、 + `Charts`、`Users`、`GameRecords`、`AssessRecords`、`AssessInfo`。 + - 使用委托模式(`SongSetDelegate`、`SongChartDelegate`、 + `GameUserDelegate` 等)将 `gateau` 接口与 MongoDB 文档桥接, + 修改后写回数据库。 - 排行榜使用 MongoDB 聚合管道(`setWindowFields`、`rank`)计算。 ## 测试 @@ -185,7 +230,9 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt 项目当前测试覆盖较少: - `booster/src/test/kotlin/TestColorOutput.kt`:JUnit 5 日志颜色冒烟测试。 -- `devtools/dynamite-cli/src/test/kotlin/TestGraphqlRequests.kt`:`kotlin.test` 集成测试,默认标记为 `@Ignore`,目标为 `localhost:10443/graphql`。 +- `devtools/dynamite-cli/src/test/kotlin/TestGraphqlRequests.kt`: + `kotlin.test` 集成测试,默认标记为 `@Ignore`, + 目标为 `localhost:10443/graphql`。 - CI 使用 `./gradlew build -x test`,因此构建不会阻塞于测试。 ## 代码风格 @@ -194,12 +241,14 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt - 缩进使用 **Tab**(`indent_style = tab`),而非空格。 - Kotlin 基本遵循旧版 IntelliJ IDEA Kotlin codestyle,例外: - - 枚举与常量命名允许 `UpperCamelCase` 或 `UPPER_SNAKE_CASE`(正则 `[A-Z][_a-zA-Z\d]*`)。 - - 控制关键字与左括号之间**不加空格**:`if(true)`、`for(...)`、`while(...)`、`catch(...)`、`when(...)`。 + - 枚举与常量命名允许 `UpperCamelCase` 或 `UPPER_SNAKE_CASE` + (正则 `[A-Z][_a-zA-Z\d]*`)。 + - 控制关键字与左括号之间**不加空格**: + `if(true)`、`for(...)`、`while(...)`、`catch(...)`、`when(...)`。 - 注解与被注解代码**换行**。 - 限制 Top Level Function 的使用范围。 - Java:IntelliJ 默认规范 + Tab 缩进 + 控制关键字前不加空格。 -- Markdown:尽量遵循 Google Markdown Style Guide。 +- Markdown:尽量遵循 Google Markdown Style Guide。每行字符数 < 80 - 编码:UTF-8。 ## 部署与 CI/CD @@ -208,16 +257,24 @@ java -cp explode-proxy--all.jar explode2.booster.BoosterMainKt - 触发条件:`v3` 分支的 push 与 pull_request。 - 运行环境:Ubuntu Latest、JDK 17 Temurin、Gradle setup action v6。 - 构建命令:`./gradlew build -x test`。 -- 上传产物:`explode-all/build/libs/`、`explode-proxy/build/libs/`、`booster-plugins/*/build/libs/`。 +- 上传产物:`explode-all/build/libs/`、`explode-proxy/build/libs/`、 + `booster-plugins/*/build/libs/`。 ## 安全与敏感信息 -- MongoDB 连接字符串等敏感信息通过环境变量或本地配置文件传入,不应提交到仓库。 -- `explode-proxy` 会将远程登录凭据缓存在运行目录的 `.proxy_cache` 文件中,该文件**不得上传或共享**;重置代理服务器时应删除它。 -- Bomb API 存在 `Superstar` 后门配置:启用后允许一个随机 UUID 账户以任意用户身份登录,仅应在受控测试环境使用。 +- MongoDB 连接字符串等敏感信息通过环境变量或本地配置文件传入, + 不应提交到仓库。 +- `explode-proxy` 会将远程登录凭据缓存在运行目录的 `.proxy_cache` 文件中, + 该文件**不得上传或共享**;重置代理服务器时应删除它。 +- Bomb API 存在 `Superstar` 后门配置:启用后允许一个随机 UUID 账户 + 以任意用户身份登录,仅应在受控测试环境使用。 ## 其他注意事项 -- 项目声明了一个 Git 子模块 `TunerGamesEncryption`(指向 `git@github.com:Taskeren/Explode-Crypto.git`),但在当前工作树中可能未检出(路径 `TunerGamesEncryption` 不存在)。 -- `src/main/kotlin/explode2/tests/Main.kt` 是开发用的临时/草稿代码,不是正式测试。 -- 新开发优先参考现有模块(如 `gatekeeper` 或 `booster-plugins/maintain`)的目录结构与 `META-INF/services` 注册方式。 +- 项目声明了一个 Git 子模块 `TunerGamesEncryption` + (指向 `git@github.com:Taskeren/Explode-Crypto.git`), + 但在当前工作树中可能未检出(路径 `TunerGamesEncryption` 不存在)。 +- `src/main/kotlin/explode2/tests/Main.kt` 是开发用的临时/草稿代码, + 不是正式测试。 +- 新开发优先参考现有模块(如 `gatekeeper` 或 `booster-plugins/maintain`) + 的目录结构与 `META-INF/services` 注册方式。 From c8ec6125d65c78cb9f14ce51d5103cddec1cfcff Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 01:53:58 +0800 Subject: [PATCH 3/8] use ignoreTrailingSlash to deal with routing --- README.md | 2 +- booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78948ce..514497b 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ Maybe you can refer to DEV_README.md? ### Env Vars -*DB_URL*: The connection string to the database. \ No newline at end of file +*DB_URL*: The connection string to the database. diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index f3ae0ab..2d4f84c 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -23,6 +23,7 @@ import io.ktor.server.auth.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* import io.ktor.server.plugins.statuspages.* +import io.ktor.server.plugins.IgnoreTrailingSlash import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* @@ -117,6 +118,8 @@ class BombPlugin : BoosterPlugin { } } + install(IgnoreTrailingSlash) + install(CORS) { // Get, Post, Head are in the default allow list, so no need to add them. allowMethod(HttpMethod.Put) @@ -170,9 +173,6 @@ private val bombModule: RouteConfigure = { route("") { get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } } - route("/") { - get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } - } // 用户接口模块 logger.debug(configureMarker, "Installing UserModule") From 1fb03265c4faf783b8ce8b5c5a12bcb02c0d146b Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 01:56:50 +0800 Subject: [PATCH 4/8] removed useless jvm17 check --- .github/workflows/gradle.yml | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 42bf551..3b1066b 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -25,33 +25,6 @@ jobs: uses: gradle/actions/setup-gradle@v6 - name: Build with Gradle run: ./gradlew build -x test - - name: Verify bytecode version (JVM 17) - run: | - JAVA17_MAJOR=61 - FAILED=0 - for jar in explode-all/build/libs/*.jar explode-proxy/build/libs/*.jar booster-plugins/*/build/libs/*.jar; do - [ -f "$jar" ] || continue - echo "Checking $jar" - FIRST_CLASS=$(unzip -Z1 "$jar" '*.class' | head -1) - if [ -n "$FIRST_CLASS" ]; then - TMPDIR=$(mktemp -d) - unzip -q -p "$jar" "$FIRST_CLASS" > "$TMPDIR/check.class" - MAJOR=$(od -An -j6 -N2 --endian=big -t u2 "$TMPDIR/check.class" | tr -d ' ') - echo " major version: $MAJOR" - rm -rf "$TMPDIR" - if [ "$MAJOR" != "$JAVA17_MAJOR" ]; then - echo " ERROR: expected $JAVA17_MAJOR, got $MAJOR" - FAILED=1 - fi - else - echo " WARNING: no .class files found" - fi - done - if [ "$FAILED" -ne 0 ]; then - echo "Bytecode version check failed!" - exit 1 - fi - echo "All checked JARs are JVM 17 bytecode (major version 61)." - name: Upload Artifacts uses: actions/upload-artifact@v4 with: From 8ae1575a09d4449f9ad4ccd9a9e3119a97eaf521 Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 01:59:31 +0800 Subject: [PATCH 5/8] - redundant "route" --- booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index 2d4f84c..baa7980 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -170,9 +170,7 @@ private val bombModule: RouteConfigure = { logger.debug(configureMarker, "Installing DefaultModule") // [/] or [] 用来测试的接口(欢迎语) - route("") { - get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } - } + get { bombCall.respondData(WelcomeBO(welcomeMessages.random()).toData()) } // 用户接口模块 logger.debug(configureMarker, "Installing UserModule") From e34fbc7babcc0cda60459b0a5a8d4138e2f74844 Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 02:02:57 +0800 Subject: [PATCH 6/8] fix compile error --- booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index baa7980..93db054 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -23,7 +23,7 @@ import io.ktor.server.auth.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* import io.ktor.server.plugins.statuspages.* -import io.ktor.server.plugins.IgnoreTrailingSlash +import io.ktor.server.plugins.ignoretrailingslash.IgnoreTrailingSlash import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* From 08ab3b51c556e73452cbe44dd248fbff76ebb0ce Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 02:18:41 +0800 Subject: [PATCH 7/8] attempt to fix compile error --- booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index 93db054..1e4d9de 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -23,7 +23,6 @@ import io.ktor.server.auth.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* import io.ktor.server.plugins.statuspages.* -import io.ktor.server.plugins.ignoretrailingslash.IgnoreTrailingSlash import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* @@ -118,7 +117,9 @@ class BombPlugin : BoosterPlugin { } } - install(IgnoreTrailingSlash) + install(Routing) { + ignoreTrailingSlash = true + } install(CORS) { // Get, Post, Head are in the default allow list, so no need to add them. From 261aa2d303ac7ba2c22c5609bd87f59b32b7d2f1 Mon Sep 17 00:00:00 2001 From: AXIS5hacker Date: Sat, 13 Jun 2026 02:25:49 +0800 Subject: [PATCH 8/8] attempt 2 --- booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt index 1e4d9de..1d7675a 100644 --- a/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt +++ b/booster/src/main/kotlin/explode2/booster/bomb/BombPlugin.kt @@ -23,6 +23,7 @@ import io.ktor.server.auth.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* import io.ktor.server.plugins.statuspages.* +import io.ktor.server.routing.IgnoreTrailingSlash import io.ktor.server.request.* import io.ktor.server.response.* import io.ktor.server.routing.* @@ -117,9 +118,7 @@ class BombPlugin : BoosterPlugin { } } - install(Routing) { - ignoreTrailingSlash = true - } + install(IgnoreTrailingSlash) install(CORS) { // Get, Post, Head are in the default allow list, so no need to add them.