Compare commits

..

190 Commits
v0.4.0 ... main

Author SHA1 Message Date
dependabot[bot]
d160fa7ee5
build(deps): bump org.jetbrains.dokka:javadoc-plugin (#187)
Bumps [org.jetbrains.dokka:javadoc-plugin](https://github.com/Kotlin/dokka) from 1.9.10 to 2.0.0.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.9.10...v2.0.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-29 17:34:24 +08:00
dependabot[bot]
b053388f82
build(deps): bump com.google.code.gson:gson from 2.10.1 to 2.11.0 (#182)
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.10.1 to 2.11.0.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/main/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.10.1...gson-parent-2.11.0)

---
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-29 15:58:06 +08:00
818cb21df7
release: 发布 0.8.0-1 版本.
这是 0.8.0 版本的重新发布版本, 由于 0.8.0 版本在构建并发布到 Maven 仓库中出现问题,
为确保本项目的“可重现构建”承诺能正常实施, 因此决定发布 0.8.0-1 版本.
该版本与 0.8.0 版本除了补充缺失的 Javadoc 外并无其他差别, 最终用户依然可以继续使用 0.8.0 版本.
2024-12-11 23:12:02 +08:00
c681ebc4c1
build: 不再使用 kuku-repo 作为发布仓库.
Some checks failed
Binary compatibility verification (for API) / apiCompatibilityCheck (push) Has been cancelled
Build and test project / build (push) Has been cancelled
Build development version container image / build (push) Has been cancelled
2024-12-11 09:47:22 +08:00
44b7b5122f
docs(extension): 补充部分缺失的 Javadoc 文档. 2024-12-11 09:46:15 +08:00
bf4adc8437
release: 发布 0.8.0 版本. 2024-12-11 09:34:32 +08:00
dependabot[bot]
47d34b0fd8
build(deps): bump docker/build-push-action from 5 to 6 (#163)
Some checks are pending
Binary compatibility verification (for API) / apiCompatibilityCheck (push) Waiting to run
Build and test project / build (push) Waiting to run
Build development version container image / build (push) Waiting to run
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 00:56:54 +08:00
dependabot[bot]
14098d285c
build(deps): bump io.mockk:mockk from 1.13.9 to 1.13.13 (#176)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.9 to 1.13.13.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.9...1.13.13)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 00:54:30 +08:00
dependabot[bot]
ad359935d6
build(deps): bump org.jetbrains.kotlinx:kotlinx-coroutines-core (#174)
Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core](https://github.com/Kotlin/kotlinx.coroutines) from 1.7.3 to 1.9.0.
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.7.3...1.9.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-11 00:51:46 +08:00
3e1bf4991d
build(deps): 将 Kotlin 更新至 2.1.0 版本. 2024-12-11 00:47:57 +08:00
bd7f556c31
build(gradle): 将 Gradle 更新至 8.11.1 版本. 2024-12-11 00:14:18 +08:00
dependabot[bot]
9c069adc4b
build(deps): bump ch.qos.logback:logback-classic from 1.4.14 to 1.5.12 (#179)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.14 to 1.5.12.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.14...v_1.5.12)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 23:54:58 +08:00
dependabot[bot]
96a06c48ee
build(deps): bump org.jetbrains.kotlinx.kover from 0.7.5 to 0.8.3 (#167)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.7.5 to 0.8.3.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/v0.7.5...v0.8.3)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 23:50:00 +08:00
ca4bfee03e
build(github-action): 将所有 Github Action 所使用的 Java 版本升级至 17. 2024-12-10 23:42:50 +08:00
16dc98fa85
Merge branch 'main' of github.com:LamGC/ScalaBot 2024-12-10 23:36:29 +08:00
8299316af8
refactor(extension): 使用 URI 而不是 URL 来排除重复项, 以避免潜在的 URL hashCode 问题. 2024-12-10 23:35:12 +08:00
e1c87aeae4
feat: 将 TelegramBots 升级至 8.0.0, 并适配 TelegramBots 的新改动.
将 TelegramBots 升级至新版本, 以支持新的 API.
由于 TelegramBots 发生无法兼容旧版本的重大变更, 因此 ScalaBot 将随着此次更新一同进行重大更改.

BREAKING CHANGE: ScalaBot 所依赖的 TelegramBots 发生重大更改, 所有扩展都需要进行适配.
  有关 TelegramBots 的重大变更说明请参考官方文档.
  ScalaBot 的最低 Java 版本已全部升级至 Java 17 (这是 TelegramBots 的最低兼容性要求), 所有扩展都应该至少迁移至 Java 17 版本.
  ScalaBot 的重大更改:
   - scalabot-extension
     - `net.lamgc.scalabot.extension.util.AbilityBots.getBotAccountId(BaseAbilityBot): long` 已被移除, 由于 BaseAbilityBot 不再允许获取 botToken, 因此该方法被移除. 作为代替, 请通过 `net.lamgc.scalabot.extension.BotExtensionFactory.createExtensionInstance` 所得到的 `BotExtensionCreateOptions` 中获取 botAccountId.

  另外, scalabot-extension 中的 `org.jetbrains.kotlinx.binary-compatibility-validator` 似乎不再对 Java 代码起作用, 因此移除该插件, 并在后续寻找替代品.
  TelegramBots 文档: https://rubenlagus.github.io/TelegramBotsDocumentation/how-to-update-7.html
2024-12-10 23:32:29 +08:00
dependabot[bot]
232e318522
build(deps): bump org.jetbrains.dokka from 1.9.10 to 1.9.20 (#147)
Some checks failed
Binary compatibility verification (for API) / apiCompatibilityCheck (push) Has been cancelled
Build and test project / build (push) Has been cancelled
Build development version container image / build (push) Has been cancelled
Bumps [org.jetbrains.dokka](https://github.com/Kotlin/dokka) from 1.9.10 to 1.9.20.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.9.10...v1.9.20)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-07 01:09:11 +08:00
bac7239513
build(action): 将 Gradle 相关 Action 迁移到官方推荐的新版本. 2024-08-30 09:00:48 +08:00
cc7ef37539
build(action): 移除 gradle/actions/wrapper-validation 并将 gradle/actions/setup-gradle 升级至 v4 版本. 2024-08-30 08:52:40 +08:00
4cf670a4d0
build(action): 将 gradle/gradle-build-action@v3.1.0 迁移至 gradle/actions/setup-gradle@v3 2024-08-30 08:45:35 +08:00
dependabot[bot]
d6781dbc71
build(deps): bump gradle/gradle-build-action from 3.1.0 to 3.4.2 (#164)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 3.1.0 to 3.4.2.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v3.1.0...v3.4.2)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 14:10:40 +08:00
63f68acccd
build(action): 将 gradle/wrapper-validation-action@v2 迁移至 gradle/actions/wrapper-validation@v3 2024-05-15 08:50:32 +08:00
506f073bf6
release: 发布 0.7.0 版本. 2024-05-15 08:32:34 +08:00
9dc4bfa28f
feat: 为 BotExtensionFactory 提供一些可用的信息. (#125)
为 BotExtensionFactory 的 createExtensionInstance 方法添加 BotExtensionCreateOptions 参数,
通过 BotExtensionCreateOptions 为扩展包 Factory 提供更多信息, 以避免扩展重复声明配置文件.

Issue #4
2024-03-25 23:22:26 +08:00
92a1deac50
build(deps): bump org.telegram:telegrambots-abilities from 6.8.0 to 6.9.7.1 2024-03-25 23:04:24 +08:00
0e2ce68a9c
feat(container): 将容器镜像的 Java 镜像由 OpenJDK:18 更改至 eclipse-temurin:21-jdk-alpine
这将有利于支持通过更高版本 Java 构建的扩展包, 且减少镜像体积.
2024-03-25 22:54:36 +08:00
d57e63f8de
build: 更新 Kotlin 版本由 1.9.22 到 1.9.23
更新 Kotlin 版本以更好的支持新特性.
2024-03-25 22:52:15 +08:00
dependabot[bot]
73653cabc6
build(deps): bump commons-codec:commons-codec from 1.16.0 to 1.16.1 (#144)
Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.16.0 to 1.16.1.
- [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.16.0...rel/commons-codec-1.16.1)

---
updated-dependencies:
- dependency-name: commons-codec:commons-codec
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 22:11:04 +08:00
dependabot[bot]
9e87591671
build(deps): bump org.mockito:mockito-core from 5.9.0 to 5.11.0 (#141)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.9.0 to 5.11.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.9.0...v5.11.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 18:10:17 +08:00
dependabot[bot]
126092487d
build(deps): bump softprops/action-gh-release from 1 to 2 (#142)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 17:16:18 +08:00
dependabot[bot]
44bc52050c
build(deps): bump gradle/wrapper-validation-action from 1 to 2 (#135)
Bumps [gradle/wrapper-validation-action](https://github.com/gradle/wrapper-validation-action) from 1 to 2.
- [Release notes](https://github.com/gradle/wrapper-validation-action/releases)
- [Commits](https://github.com/gradle/wrapper-validation-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: gradle/wrapper-validation-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 16:26:35 +08:00
dependabot[bot]
f809076df0
build(deps): bump org.jetbrains.kotlinx.binary-compatibility-validator (#134)
Bumps [org.jetbrains.kotlinx.binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) from 0.13.2 to 0.14.0.
- [Release notes](https://github.com/Kotlin/binary-compatibility-validator/releases)
- [Commits](https://github.com/Kotlin/binary-compatibility-validator/compare/0.13.2...0.14.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.binary-compatibility-validator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 16:21:33 +08:00
dependabot[bot]
b34f05a90b
build(deps): bump gradle/gradle-build-action from 2.11.1 to 3.1.0 (#140)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.11.1 to 3.1.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.11.1...v3.1.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 16:12:29 +08:00
dependabot[bot]
ddc4de1340
build(deps): bump io.mockk:mockk from 1.13.8 to 1.13.9 (#123)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.8 to 1.13.9.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/commits)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-21 23:28:07 +08:00
dependabot[bot]
a9134f378e
build(deps): bump org.slf4j:slf4j-api from 2.0.9 to 2.0.11 (#124)
Bumps org.slf4j:slf4j-api from 2.0.9 to 2.0.11.

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-21 23:23:37 +08:00
dependabot[bot]
dbb2fcdee1
build(deps): bump org.mockito:mockito-core from 5.8.0 to 5.9.0 (#128)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.8.0 to 5.9.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.8.0...v5.9.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-21 23:17:55 +08:00
dependabot[bot]
ce00369a22
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#120)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.9.21 to 1.9.22.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.21...v1.9.22)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 19:31:51 +08:00
dependabot[bot]
65bac28303
build(deps): bump jvm from 1.9.10 to 1.9.22 (#119)
Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.9.10 to 1.9.22.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.10...v1.9.22)

---
updated-dependencies:
- dependency-name: jvm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 18:47:23 +08:00
dependabot[bot]
8bd6d5ffe5
build(deps): bump ch.qos.logback:logback-classic from 1.4.11 to 1.4.14 (#118)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.11 to 1.4.14.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.14)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 17:42:06 +08:00
dependabot[bot]
1c4cc122c9
build(deps): bump org.jetbrains.kotlinx.kover from 0.7.4 to 0.7.5 (#117)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.7.4 to 0.7.5.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/0.7.4...v0.7.5)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 17:41:57 +08:00
dependabot[bot]
6083f4fc68
build(deps): bump org.junit.jupiter:junit-jupiter-api (#115)
Bumps [org.junit.jupiter:junit-jupiter-api](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 17:41:41 +08:00
dependabot[bot]
b33de4d63a
build(deps): bump gradle/gradle-build-action from 2.11.0 to 2.11.1 (#121)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.11.0 to 2.11.1.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.11.0...v2.11.1)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-07 17:41:27 +08:00
fd67eb99eb
feat: 在启动机器人时调用 GetMe 接口, 以检查 Token 有效性.
通过这种方式, 可以帮助用户在启动阶段发现 Bot Token 无效的问题.
2023-12-18 22:21:58 +08:00
ba306e679f
build(deps): bump all telegrambots deps from 6.7.0 to 6.8.0 (#114)
Bumps [org.telegram:telegrambots](https://github.com/rubenlagus/TelegramBots) from 6.7.0 to 6.8.0.
- [Release notes](https://github.com/rubenlagus/TelegramBots/releases)
- [Commits](rubenlagus/TelegramBots@v6.7.0...v6.8.0)

---
updated-dependencies:
- dependency-name: org.telegram:telegrambots-abilities
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.telegram:telegrambots
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.telegram:telegrambots-meta
  dependency-type: direct:production
  update-type: version-update:semver-minor
...
2023-12-17 23:10:52 +08:00
dependabot[bot]
f188d5bfa9
build(deps): bump org.mockito:mockito-core from 5.6.0 to 5.8.0 (#111)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.6.0 to 5.8.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.6.0...v5.8.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-17 22:49:24 +08:00
dependabot[bot]
376086daa1
build(deps): bump org.junit.jupiter:junit-jupiter-engine (#112)
Bumps [org.junit.jupiter:junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-engine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-17 22:42:54 +08:00
dependabot[bot]
cee8797c40
build(deps): bump org.jetbrains.dokka:javadoc-plugin (#103)
Bumps [org.jetbrains.dokka:javadoc-plugin](https://github.com/Kotlin/dokka) from 1.9.0 to 1.9.10.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.9.0...v1.9.10)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 12:16:49 +08:00
dependabot[bot]
77b5867dd7
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#105)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.9.10 to 1.9.21.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.10...v1.9.21)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 12:16:37 +08:00
dependabot[bot]
33eefd9e60
build(deps): bump gradle/gradle-build-action from 2.9.0 to 2.11.0 (#110)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.9.0 to 2.11.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.9.0...v2.11.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 12:16:10 +08:00
dependabot[bot]
0c81ca6d5f
build(deps): bump actions/setup-python from 4 to 5 (#108)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 12:15:57 +08:00
dependabot[bot]
705150b961
build(deps): bump actions/setup-java from 3 to 4 (#106)
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3 to 4.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-15 12:09:50 +08:00
dependabot[bot]
e6f0550985
build(deps): bump org.jetbrains.dokka from 1.9.0 to 1.9.10 (#102)
Bumps [org.jetbrains.dokka](https://github.com/Kotlin/dokka) from 1.9.0 to 1.9.10.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.9.0...v1.9.10)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-04 08:41:26 +08:00
dependabot[bot]
90c57ff9b1
build(deps): bump org.mockito:mockito-core from 5.5.0 to 5.6.0 (#100)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.5.0 to 5.6.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.5.0...v5.6.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-31 13:37:50 +08:00
dependabot[bot]
d773cba776
build(deps): bump org.jetbrains.kotlinx.kover from 0.7.3 to 0.7.4 (#101)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.7.3 to 0.7.4.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/v0.7.3...0.7.4)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-31 13:37:30 +08:00
dependabot[bot]
f1c36aacdb
build(deps): bump io.mockk:mockk from 1.13.7 to 1.13.8 (#97)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.7 to 1.13.8.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.7...1.13.8)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-03 00:59:36 +08:00
dependabot[bot]
fe9e7059c8
build(deps): bump gradle/gradle-build-action from 2.8.0 to 2.9.0 (#99)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.8.0 to 2.9.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.8.0...v2.9.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 22:22:51 +08:00
dependabot[bot]
b42cc6bd2c
build(deps): bump docker/setup-qemu-action from 2 to 3 (#94)
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:46:49 +08:00
dependabot[bot]
ebfc387505
build(deps): bump docker/build-push-action from 4 to 5 (#96)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:46:39 +08:00
dependabot[bot]
340f6ba3f3
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#91)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.9.0 to 1.9.10.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.9.10/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.0...v1.9.10)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:46:13 +08:00
dependabot[bot]
e8f9dbbb05
build(deps): bump org.jetbrains.dokka from 1.8.20 to 1.9.0 (#92)
Bumps [org.jetbrains.dokka](https://github.com/Kotlin/dokka) from 1.8.20 to 1.9.0.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.8.20...v1.9.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:02:31 +08:00
dependabot[bot]
cdbfa822b0
build(deps): bump docker/setup-buildx-action from 2 to 3 (#93)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:02:07 +08:00
dependabot[bot]
6d5ce324a5
build(deps): bump docker/login-action from 2 to 3 (#95)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 01:01:47 +08:00
dependabot[bot]
734a871fdc
build(deps): bump org.slf4j:slf4j-api from 2.0.7 to 2.0.9 (#88)
Bumps org.slf4j:slf4j-api from 2.0.7 to 2.0.9.

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-24 00:57:50 +08:00
dependabot[bot]
a9ee432dec
build(deps): bump io.mockk:mockk from 1.13.5 to 1.13.7 (#81)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.5 to 1.13.7.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/commits)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-15 10:33:55 +08:00
dependabot[bot]
1fc386a226
build(deps): bump org.mockito:mockito-core from 5.3.1 to 5.5.0 (#83)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.3.1 to 5.5.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.3.1...v5.5.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-15 10:30:14 +08:00
dependabot[bot]
40524e89c6
build(deps): bump org.jetbrains.dokka:javadoc-plugin (#86)
Bumps [org.jetbrains.dokka:javadoc-plugin](https://github.com/Kotlin/dokka) from 1.8.20 to 1.9.0.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.8.20...v1.9.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 23:12:21 +08:00
dependabot[bot]
c972759ffb
build(deps): bump org.junit.jupiter:junit-jupiter-engine (#76)
Bumps [org.junit.jupiter:junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.9.3 to 5.10.0.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-engine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 17:50:02 +08:00
dependabot[bot]
9b169ac957
build(deps): bump ch.qos.logback:logback-classic from 1.4.8 to 1.4.11 (#80)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.8 to 1.4.11.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.8...v_1.4.11)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 17:42:21 +08:00
f93a41af96
chore(meta): 确认由 Kotlin 版本更新导致的 api 变动.
自 Kotlin 1.9.0 开始, `Enum.values` 将正式更改为 `Enum.getEntries`(对应 Kotlin 中的
`Enum.entries` 属性), 已确认该改动不会影响现版本的兼容性.
--------------------------
KEEP 文档:
https://github.com/Kotlin/KEEP/blob/master/proposals/enum-entries.md
Kotlin 问题跟踪器:
https://youtrack.jetbrains.com/issue/KT-48872
2023-09-14 13:33:04 +08:00
dependabot[bot]
8eb993da3e
build(deps): bump actions/checkout from 3 to 4 (#87)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 11:43:11 +08:00
dependabot[bot]
9065df0e04
build(deps): bump jvm from 1.8.21 to 1.9.10 (#84)
Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.8.21 to 1.9.10.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.9.10/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.21...v1.9.10)

---
updated-dependencies:
- dependency-name: jvm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-09 23:19:55 +08:00
dependabot[bot]
9514c7b57e
build(deps): bump gradle/gradle-build-action from 2.7.0 to 2.8.0 (#85)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.7.0...v2.8.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-09 23:10:11 +08:00
24219df63b
release: 发布 6.1.0 版本. 2023-08-03 09:11:28 +08:00
dependabot[bot]
14e9c4d686
build(deps): bump org.jetbrains.dokka from 1.8.10 to 1.8.20 (#72)
Bumps [org.jetbrains.dokka](https://github.com/Kotlin/dokka) from 1.8.10 to 1.8.20.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.8.10...v1.8.20)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 18:29:25 +08:00
dependabot[bot]
8e83f714a7
build(deps): bump org.jetbrains.kotlinx:kotlinx-coroutines-core (#74)
Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core](https://github.com/Kotlin/kotlinx.coroutines) from 1.7.1 to 1.7.3.
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.7.1...1.7.3)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 18:12:12 +08:00
dependabot[bot]
939aed5850
build(deps): bump ch.qos.logback:logback-classic from 1.4.7 to 1.4.8 (#73)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.7 to 1.4.8.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.7...v_1.4.8)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 18:08:43 +08:00
dependabot[bot]
a839cc63e6
build(deps): bump org.junit.jupiter:junit-jupiter-api (#71)
Bumps [org.junit.jupiter:junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.3 to 5.10.0.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.0)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:58:19 +08:00
dependabot[bot]
8be3f770bf
build(deps): bump commons-codec:commons-codec from 1.15 to 1.16.0 (#75)
Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.15 to 1.16.0.
- [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.15...rel/commons-codec-1.16.0)

---
updated-dependencies:
- dependency-name: commons-codec:commons-codec
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:54:46 +08:00
b1e7643b09
build(deps): 将 telegrambots 从 6.5.0 更新至 6.7.0
更新 Api 版本以支持新的 Api 改动.
2023-08-02 17:45:35 +08:00
4537e08107
fix(config): 将 local 列为 Maven 仓库 Id 的保留字.
local 是 Aether 中代表 LocalRepository 的仓库 Id, 因此拒绝用户使用 local 作为远端仓库的 Id.
2023-08-02 17:45:31 +08:00
3ea1eec2dd
ci(github-action): 提高 dependabot 依赖项更新检查的频率
提高检查频率, 以加快新版本的响应.
2023-08-02 17:40:35 +08:00
dependabot[bot]
fe9978dbe8
build(deps): bump org.jetbrains.kotlinx.kover from 0.7.0 to 0.7.3 (#69)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.7.0 to 0.7.3.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/v0.7.0...v0.7.3)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:12:57 +08:00
dependabot[bot]
aece8221f1
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#68)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.8.21 to 1.9.0.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.21...v1.9.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:08:50 +08:00
dependabot[bot]
4c9256f82f
build(deps): bump org.telegram:telegrambots-meta from 6.5.0 to 6.7.0 (#64)
Bumps [org.telegram:telegrambots-meta](https://github.com/rubenlagus/TelegramBots) from 6.5.0 to 6.7.0.
- [Release notes](https://github.com/rubenlagus/TelegramBots/releases)
- [Commits](https://github.com/rubenlagus/TelegramBots/compare/v6.5.0...v6.7.0)

---
updated-dependencies:
- dependency-name: org.telegram:telegrambots-meta
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 17:04:47 +08:00
dependabot[bot]
3f2e4e2d1f
build(deps): bump org.jetbrains.dokka:javadoc-plugin (#63)
Bumps [org.jetbrains.dokka:javadoc-plugin](https://github.com/Kotlin/dokka) from 1.8.10 to 1.8.20.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/compare/v1.8.10...v1.8.20)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 16:59:18 +08:00
dependabot[bot]
3810224667
build(deps): bump org.jetbrains.kotlinx.binary-compatibility-validator (#61)
Bumps [org.jetbrains.kotlinx.binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) from 0.13.1 to 0.13.2.
- [Release notes](https://github.com/Kotlin/binary-compatibility-validator/releases)
- [Commits](https://github.com/Kotlin/binary-compatibility-validator/compare/0.13.1...0.13.2)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.binary-compatibility-validator
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 16:39:17 +08:00
dependabot[bot]
3241bd2da9
build(deps): bump younited/get-previous-tag-action from 1.0.0 to 1.1.0 (#60)
Bumps [younited/get-previous-tag-action](https://github.com/younited/get-previous-tag-action) from 1.0.0 to 1.1.0.
- [Release notes](https://github.com/younited/get-previous-tag-action/releases)
- [Commits](https://github.com/younited/get-previous-tag-action/compare/v1.0.0...v1.1.0)

---
updated-dependencies:
- dependency-name: younited/get-previous-tag-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 13:57:51 +08:00
dependabot[bot]
dcac53fe65
build(deps): bump gradle/gradle-build-action from 2.4.2 to 2.7.0 (#70)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.4.2 to 2.7.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.4.2...v2.7.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-01 19:01:48 +08:00
dependabot[bot]
0bc77ada5f
build(deps): bump org.jetbrains.kotlinx:kotlinx-coroutines-core (#58)
Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core](https://github.com/Kotlin/kotlinx.coroutines) from 1.6.4 to 1.7.1.
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.6.4...1.7.1)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-30 10:44:16 +08:00
dependabot[bot]
f0b45568d1
build(deps): bump org.junit.jupiter:junit-jupiter-engine (#59)
Bumps [org.junit.jupiter:junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.9.2 to 5.9.3.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-engine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-30 10:36:30 +08:00
dependabot[bot]
a3dd9d4114
build(deps): bump org.jetbrains.kotlinx.kover from 0.6.1 to 0.7.0 (#57)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.6.1 to 0.7.0.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/v0.6.1...v0.7.0)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-30 10:31:55 +08:00
dependabot[bot]
3afe3b52ed
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#56)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.8.20 to 1.8.21.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.20...v1.8.21)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 10:14:34 +08:00
dependabot[bot]
bdf75f1046
build(deps): bump org.junit.jupiter:junit-jupiter-api (#54)
Bumps [org.junit.jupiter:junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.2 to 5.9.3.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:46:58 +08:00
dependabot[bot]
e834d4c7c7
build(deps): bump jvm from 1.8.20 to 1.8.21 (#53)
Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.8.20 to 1.8.21.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.20...v1.8.21)

---
updated-dependencies:
- dependency-name: jvm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:40:53 +08:00
dependabot[bot]
2e1fae87b3
build(deps): bump ch.qos.logback:logback-classic from 1.4.6 to 1.4.7 (#50)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.6 to 1.4.7.
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.6...v_1.4.7)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:33:17 +08:00
dependabot[bot]
191bef5d68
build(deps): bump org.jetbrains.kotlinx.binary-compatibility-validator (#49)
Bumps [org.jetbrains.kotlinx.binary-compatibility-validator](https://github.com/Kotlin/binary-compatibility-validator) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/Kotlin/binary-compatibility-validator/releases)
- [Commits](https://github.com/Kotlin/binary-compatibility-validator/compare/0.13.0...0.13.1)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.binary-compatibility-validator
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:24:24 +08:00
dependabot[bot]
55c435c4c0
build(deps): bump gradle/gradle-build-action in /.github/workflows (#55)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.4.0 to 2.4.2.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.4.0...v2.4.2)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-16 09:14:13 +08:00
dependabot[bot]
758e0a9f16
build(deps): bump org.mockito:mockito-core from 5.3.0 to 5.3.1 (#51)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.3.0 to 5.3.1.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.3.0...v5.3.1)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-11 14:28:55 +08:00
dependabot[bot]
5814817f3a
build(deps): bump org.mockito:mockito-core from 5.2.0 to 5.3.0 (#47)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.2.0...v5.3.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-23 23:40:48 +08:00
dependabot[bot]
2641901240
build(deps): bump io.mockk:mockk from 1.13.4 to 1.13.5 (#48)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.4 to 1.13.5.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/v1.13.4...1.13.5)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-20 17:54:51 +08:00
dependabot[bot]
0070b400bb
build(deps): bump org.jetbrains.dokka:javadoc-plugin (#40)
Bumps [org.jetbrains.dokka:javadoc-plugin](https://github.com/Kotlin/dokka) from 1.7.20 to 1.8.10.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/commits)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka:javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 18:57:09 +08:00
dependabot[bot]
73e20ab737
build(deps): bump ch.qos.logback:logback-classic from 1.4.5 to 1.4.6 (#44)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.5 to 1.4.6.
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.5...v_1.4.6)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 18:56:57 +08:00
dependabot[bot]
03d24fbfe3
build(deps): bump org.jetbrains.kotlin:kotlin-reflect (#45)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.8.10 to 1.8.20.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.8.20/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.10...v1.8.20)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 18:56:36 +08:00
dependabot[bot]
53e47353e8
build(deps): bump kotlin plugin from 1.8.10 to 1.8.20 (#46)
Bumps [jvm](https://github.com/JetBrains/kotlin) from 1.8.10 to 1.8.20.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.8.20/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.8.10...v1.8.20)

---
updated-dependencies:
- dependency-name: jvm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 18:56:23 +08:00
dependabot[bot]
81a97ee8e3
build(deps): bump org.jetbrains.dokka from 1.7.20 to 1.8.10 (#41)
Bumps [org.jetbrains.dokka](https://github.com/Kotlin/dokka) from 1.7.20 to 1.8.10.
- [Release notes](https://github.com/Kotlin/dokka/releases)
- [Commits](https://github.com/Kotlin/dokka/commits)

---
updated-dependencies:
- dependency-name: org.jetbrains.dokka
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-31 13:57:26 +08:00
dependabot[bot]
dbcbc88e1b
build(deps): bump io.mockk:mockk from 1.13.2 to 1.13.4 (#38)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.2 to 1.13.4.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.2...v1.13.4)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 21:29:01 +08:00
dependabot[bot]
f233a25323
build(deps): bump org.slf4j:slf4j-api from 2.0.6 to 2.0.7 (#43)
Bumps [org.slf4j:slf4j-api](https://github.com/qos-ch/slf4j) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/qos-ch/slf4j/releases)
- [Commits](https://github.com/qos-ch/slf4j/commits)

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 21:28:20 +08:00
dependabot[bot]
2c91884db8
build(deps): bump org.mockito:mockito-core from 5.1.1 to 5.2.0 (#42)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.1.1 to 5.2.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.1.1...v5.2.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-23 21:26:44 +08:00
6b92b7e377
build(publish): 增加 self-git Maven 仓库.
目前 Gitea 的构件仓库已经完善到基本可用的程度, 决定将 extension 和 meta 模块也一同发布到 self-git 中.
2023-02-25 17:14:03 +08:00
375b815659
build(deps): extension 模块不再引入 Slf4j-api 依赖.
考虑到发布的频率, 决定不再为 extension 引入 slf4j-api 依赖;
不过还是建议开发者使用 Slf4j-api 打印日志, 这样可以将日志整合在一起, 方便排查问题.
2023-02-25 17:11:27 +08:00
f26d642320
build(gradle): 将 extension 模块的构建插件改为 java-library
先前由于不了解 Gradle 的插件划分而使用了 kotlin-jvm 插件, 现在将其修正, 改用 java-library 插件.
2023-02-24 15:55:58 +08:00
2db0b78962
style(extension): 为 getBotToken 设置 SuppressWarnings 用于忽略无关的弃用警告.
根据文档说明, 弃用仅针对重写方法, 对方法的使用并无大碍.
2023-02-24 15:53:32 +08:00
8b76a9aa9b
release: 发布 0.6.0 版本. 2023-02-21 23:46:48 +08:00
bbc3288535
ci(github-action): 启用 API 二进制兼容性验证. (#37)
使用二进制兼容验证, 可以快速了解 API 是否出现修改, 这个功能有利于防止无意中修改 API.
引入该过程后, 需谨慎检查 api 列表,
以确保改动是必须的. 当 api 出现改动时, 需按照改动类型分配合适的版本号(遵循 SemVer 规范).
2023-02-21 23:22:40 +08:00
dependabot[bot]
45ad734c7b
build(deps): bump org.junit.jupiter:junit-jupiter-engine (#34)
Bumps [org.junit.jupiter:junit-jupiter-engine](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-engine
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 18:52:21 +08:00
dependabot[bot]
1eaed8ce6f
build(deps): bump org.mockito:mockito-core from 4.8.0 to 5.1.1 (#35)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 4.8.0 to 5.1.1.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v4.8.0...v5.1.1)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 18:42:42 +08:00
dependabot[bot]
a624fcd37d
build(deps): bump com.google.code.gson:gson from 2.9.0 to 2.10.1 (#36)
Bumps [com.google.code.gson:gson](https://github.com/google/gson) from 2.9.0 to 2.10.1.
- [Release notes](https://github.com/google/gson/releases)
- [Changelog](https://github.com/google/gson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/gson/compare/gson-parent-2.9.0...gson-parent-2.10.1)

---
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 18:38:18 +08:00
dependabot[bot]
59aa83c93e
build(deps): bump org.junit.jupiter:junit-jupiter-api (#33)
Bumps [org.junit.jupiter:junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 18:36:02 +08:00
3ea0f4eacb
feat(metrics): 指标信息增加 bot_id label.
由于 bot_name 不能作为机器人的唯一标识, 因此增加 bot_id 为监控平台提供唯一标识.
2023-02-21 18:32:35 +08:00
d3e18d80ca
ci(github-action): 移除针对子模块的依赖项更新.
根据目前的效果来看, 即使不指定子模块的路径, dependabot 也会检查子模块的依赖项更新情况, 因此尝试移除子模块配置.
2023-02-21 16:00:08 +08:00
1e0eebbd7e
build(deps): 更新日志相关依赖(Slf4j 2.0.6, Logback-classic 1.4.5, Kotlin-logging 3.0.5).
Slf4j: 2.0.3 -> 2.0.6
Logback-classic: 1.4.4 -> 1.4.5
Kotlin-logging: 3.0.2 -> 3.0.5
2023-02-21 15:51:28 +08:00
dependabot[bot]
6f3c1ec592
build(deps): bump org.junit.jupiter:junit-jupiter-api (#19)
Bumps [org.junit.jupiter:junit-jupiter-api](https://github.com/junit-team/junit5) from 5.9.0 to 5.9.2.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.9.0...r5.9.2)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 15:29:54 +08:00
dependabot[bot]
c013dafdd7
build(deps): bump io.mockk:mockk from 1.13.2 to 1.13.4 in /scalabot-app (#26)
Bumps [io.mockk:mockk](https://github.com/mockk/mockk) from 1.13.2 to 1.13.4.
- [Release notes](https://github.com/mockk/mockk/releases)
- [Commits](https://github.com/mockk/mockk/compare/1.13.2...v1.13.4)

---
updated-dependencies:
- dependency-name: io.mockk:mockk
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 15:08:06 +08:00
dependabot[bot]
e0bfd8796c
build(deps): bump org.jetbrains.kotlin:kotlin-reflect in /scalabot-app (#29)
Bumps [org.jetbrains.kotlin:kotlin-reflect](https://github.com/JetBrains/kotlin) from 1.6.20 to 1.8.10.
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.8.10/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.6.20...v1.8.10)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-reflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 15:07:45 +08:00
dependabot[bot]
67d561c0ab
build(deps): bump org.jetbrains.kotlinx.kover from 0.5.1 to 0.6.1 (#32)
Bumps [org.jetbrains.kotlinx.kover](https://github.com/Kotlin/kotlinx-kover) from 0.5.1 to 0.6.1.
- [Release notes](https://github.com/Kotlin/kotlinx-kover/releases)
- [Changelog](https://github.com/Kotlin/kotlinx-kover/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Kotlin/kotlinx-kover/compare/v0.5.1...v0.6.1)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx.kover
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 12:53:54 +08:00
63687da0bb
build(dependencies): 更新 binary-compatibility-validator 插件(0.11.1 -> 0.13.0).
更新后插件将支持 Kotlin 1.8.10 版本.
2023-02-21 12:44:06 +08:00
dependabot[bot]
cd76249c33
build(deps): bump gradle/gradle-build-action from 2.2.1 to 2.4.0 (#23)
Bumps [gradle/gradle-build-action](https://github.com/gradle/gradle-build-action) from 2.2.1 to 2.4.0.
- [Release notes](https://github.com/gradle/gradle-build-action/releases)
- [Commits](https://github.com/gradle/gradle-build-action/compare/v2.2.1...v2.4.0)

---
updated-dependencies:
- dependency-name: gradle/gradle-build-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 11:24:23 +08:00
dependabot[bot]
5a8afd1549
build(deps): bump docker/build-push-action from 3 to 4 (#18)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 11:21:09 +08:00
651569dc8f
ci(github-action): 增加 Dependabot 配置文件.
使用 Dependabot 来自动检查依赖新版本, 减轻工作量.
2023-02-21 10:51:30 +08:00
bf2ea9a367
refactor(launch): 在启动时输出 JVM 和 Kotlin 的版本号.
在日志中添加版本信息, 方便在反馈问题时可以了解出现问题所使用的环境.
2023-02-19 16:12:15 +08:00
540fe84f26
build(dependencies): 更新 Kotlin 版本(1.7.10 -> 1.8.10).
更新 Kotlin 版本, 支持新的平台优化.
2023-02-19 16:09:52 +08:00
712378b3ff
build(dependencies): 更新 telegrambots 依赖项.
将 telegrambots 依赖项更新至 6.5.0, 支持新版 Api;
已确认 telegrambots 6.5.0 版本升级了jackson-databind 版本,
因此移除 jackson-databind 的显性依赖声明.
2023-02-08 10:12:33 +08:00
961382fb56
build(dependencies): 更新 TelegramBots 依赖项的版本号.
将 TelegramBots 依赖版本升级至 6.3.0, 支持新的 Telegram Bot API.
2022-12-16 01:15:09 +08:00
34d9ece6d7
feat(logging): 支持通过参数控制日志输出级别.
通过添加新的 -D 参数 `scalabot.log.level`, 使得用户可以根据需要, 调整日志输出级别, 通过日志来自行(或协助开发者)排查问题,
对于与网络有关的 Debug 级别日志, 则由 `scalabot.log.network.verbose` 参数进行控制;
另外, 由于开发过程中可通过该参数修改日志级别, 因此移除 `logback-test.xml` 文件.
2022-11-11 18:17:05 +08:00
30a2cb34d5
refactor(launch): 将 AppPaths 从 Launcher 解耦.
解耦后有助于后续改进, 以及单元测试的编写.
2022-11-07 11:16:41 +08:00
c94e0476b5
refactor(metrics): 为指标增加 namespace 名称.
遵循 OpenMetrics 规范指南, 为运行指标添加 namespace 名称, 防止指标混乱.

BREAKING CHANGE: 运行指标名称变更,
如果用户启用了运行指标功能, 请注意修改使用指标的名称.
2022-10-28 01:33:03 +08:00
6e5cd07c51
build(dependencies): 更新依赖项版本.
更新与日志和测试有关的依赖项版本.
2022-10-25 17:18:24 +08:00
d4b1438b0b
release: 发布 0.5.2 版本. 2022-10-20 16:04:27 +08:00
90110335f5
fix: 更新 jackson-databind 依赖版本以缓解 CVE-2022-42004 漏洞.
CVE-2022-42004 漏洞报告指出, 由于 jackson-databind 的有关错误, 导致对象序列化过程可能存在数据错误的问题,
目前 jackson-databind 已发布 2.13.4.2 版本以解决该问题, 由于引入 jackson-databind 的 telegrambots 库尚未发布针对该问题的修复版本,
故在本项目中引入新版依赖项, 以确保用户不受该问题影响.
该版本已在 TelegramBots 项目(版本 6.1.0)中进行测试, 测试通过.
------------------------------------------
https://devhub.checkmarx.com/cve-details/CVE-2022-42004/
2022-10-20 01:41:48 +08:00
9c32d26c0d
fix(dependencies): 更新 Commons-codec 依赖项的版本.
由于目前从 TelegramBots-Abilities 引入的 Commons-codec 存在 Base 32 和 64 的编解码漏洞,
考虑到需要防范潜在的安全问题, 因此决定更新 Commons-codec
的版本号.
----------------
参考链接:
https://devhub.checkmarx.com/cve-details/Cxeb68d52e-5509/
2022-09-19 14:32:40 +08:00
dfab6b14bd
build(compatibility): 新增 API 兼容性检查插件(尚未启用).
新增 Jetbrains 的二进制兼容性验证插件, 该插件可确保在兼容性出现更改时及时报告出来.
计划在下一次发布版本时启用.
2022-09-19 14:28:06 +08:00
437cee499a
build(dependencies): 更新依赖项版本.
更新版本有利于维持项目安全性.
2022-09-19 01:14:31 +08:00
4c30a1ac68
ci(github-action): 更改工作流名称.
后续可能会加上 Maven 的发布, 所以把名字和文件名都改一下, 防止出现歧义.
2022-08-25 16:11:10 +08:00
3932db11a1
release: 发布 0.5.1 版本. 2022-08-23 13:40:21 +08:00
d18c059498
ci(github-action): 显性声明允许工作流写入仓库.
安全起见, 仓库将设置工作流的 Github Token 默认不可写, 因此需要在该工作流添加权限声明, 以支持其创建 Release.
2022-08-23 13:40:20 +08:00
e6b581b8cd
ci(github-action): 移除容器镜像对 windows-amd64 的构建.
windows-amd64 的镜像构建依然不太不稳定, 因此移除 windows-amd64 平台的镜像构建.
2022-08-23 13:40:18 +08:00
26d7443c87
ci(github-action): 把 Gradle Wrapper 检查步骤加入到所有构建工作流中.
单独检查 Wrapper 并不能阻止其他工作流被恶意 jar 影响, 所以取消单独的检查工作流, 并将检查步骤插入到其他构建工作流中.
2022-08-23 13:40:17 +08:00
2bf4eb684e
ci(github-action): 延长镜像构建工作流的超时时间.
鉴于镜像构建可能会很慢, 因此将时间统一延长到 15 分钟.
2022-08-23 13:40:15 +08:00
5251b62733
ci(github-action): 修改开发版镜像构建工作流的名称和配置文件名.
为了与发布版镜像构建工作流区分开来, 防止弄混乱了.
2022-08-23 13:40:13 +08:00
3ec5a8e9c3
ci(github-action): 增加自动发布工作流.
使用 Action 自动执行发布过程, 可避免不少发布问题(比如构建成品包括了其他代码, 内容错误等).
同时在确认发布版本后,将自动构建并发布容器镜像, 支持多平台.
2022-08-23 13:40:11 +08:00
62f6c08cd2
ci(github-action): 移除对测试分支的容器镜像构建.
因为要并入 main 分支了.
2022-08-23 13:40:09 +08:00
5e6f64f056
ci(github-action): 尝试为 Windows 平台构建容器镜像.
看 OpenJdk 18 应该是有对 Windows/amd64 支持的, 所以添加上去, 看看能不能构建成功.
2022-08-23 13:40:07 +08:00
a036695330
ci(github-action): 修复推送 tag 错误的问题.
修复一下这个问题, 如果不加用户名, 就会推送到 library 去.
2022-08-23 13:40:05 +08:00
e9c975f5c5
ci(github-action): 更改容器发布配置名称
忘记改名字了, 改名后会更好的识别工作流.
2022-08-23 13:40:02 +08:00
9aac42d414
ci(github-action): 增加一段容器构建发布配置.
试一下看看能不能生成容器, 如果可以的话就整合到发布工作流中.
2022-08-23 13:39:58 +08:00
5add6d9909
build(container): 增加一个 Docker Context 过滤文件.
该文件用于优化向 Docker Daemon 发送 Context 文件的文件数量, 增加之后, 从四千个文件降至143个文件, 优化显著.
2022-08-23 13:39:56 +08:00
eee6b7d2c9
build(container): 新增一个比较基础的 Dockerfile.
初步测试了一下运行, 没啥问题.
2022-08-23 13:39:53 +08:00
ff396425a7
refactor: 补充缺失代码.
由于先前的修改导致代码缺失, 我现在同意暂存功能很好用了.
2022-08-18 01:06:54 +08:00
580d9122e5
refactor(utils): 把日志记录器的获取方式改的优雅一点(对于测试来说).
由于 Kover 一直不把无代码高阶函数忽略掉, 所以稍微改一下这个日志记录器的获取方法, 让测试覆盖数据好看点(doge).
2022-08-17 23:01:06 +08:00
2a607f1129
fix(extension): 修复 ExtensionClassLoader 无法过滤非扩展包内 BotExtensionFactory 对象的问题.
按照 ServiceLoader 的规范, 文件应该是在 META-INF/services/{class} 这里的, 但当时忘记这个设计了, 导致直接判断 name == class, 然后失效.
修复好了.
2022-08-15 02:00:34 +08:00
2d6da7c1ae
build(test): 添加 Jacoco 插件.
给 Extension 模块添加 Jacoco 插件, 以后估计会开 Codecov 来统计测试覆盖率.
2022-08-15 01:45:22 +08:00
6235c5f51a
build(dependencies): 更新 Kotlin 版本(1.6.10 -> 1.7.10). 2022-08-15 01:39:08 +08:00
255a02c93c
refactor(config): 重构 AppPaths 的构造方法, 应对将来 Kotlin 更新中的特性.
先前的方法是利用了初始化与调用的顺序, 来实现的 Supplier 互补(虽然在代码中, 确实存在未初始化调用的情况, 但实际运行的时候, 会先初始化, 再调用 Supplier),
但是未来 Kotlin 的更新中,编译器会把这个操作视为未初始化错误, 所以在这次改动中修复掉这个 bug 操作.
2022-08-15 01:38:08 +08:00
dce28be9c7
fix(logging): 修复日志滚动文件路径错误.
由于在滚动格式中没有使用 DATA_LOGS 占位符, 导致在日志滚动时会把日志归档文件保存在运行目录下, 而不是指定的数据目录,
该改动已修复该问题.
2022-08-13 13:19:09 +08:00
673c6d8392
build: 为项目支持可重现构建.
为确保项目的使用者(无论是开发者, 还是最终用户)可以完全重现构建, 确保安全, 故调整相关配置, 以实现"可重现构建".
有关可重现构建, 可以看这个: https://reproducible-builds.org/
2022-08-06 03:23:35 +08:00
d586ca378e
fix(launch): 修复缺省的 Maven 中央库不遵循代理规则的问题.
这个属于漏网之鱼, 已修复.
2022-08-05 00:23:13 +08:00
3ba4364a07
test(config): 补全对 ProxyConfig 的单元测试.
先前加了个 ProxyConfig.toString 方法, 所以补充了一下测试项.
2022-08-04 19:13:45 +08:00
eda0e522cd
docs(config): 补充关于 Gson 类型适配器的使用指导.
为 AppConfig 和 BotConfig 补充关于 Gson 类型适配器使用的信息, 以便于开发者正确使用类型适配器解析和编码 Json.
2022-07-22 21:59:14 +08:00
c7fedf3882
release: 发布 0.5.0 版本. 2022-07-19 01:51:00 +08:00
a7de85eacb
test(extension): 修正更新 TelegramBots 依赖项所导致的测试错误.
忘记执行测试了, 我的锅)
2022-07-16 21:03:12 +08:00
b6013e2fbe
refactor(extension): 将构件下载请求跟构件解析请求对齐.
防止在构件处理过程中因仓库原因出现问题, 因此统一两个请求所使用的仓库列表.
2022-07-16 20:55:24 +08:00
f79a4e4ff3
refactor(extension): 在 MavenRepositoryExtensionFinder 增加一个扩展包信息日志.
当初写的时候没留意这个问题, 结果最近给坑了, 所以补个日志, 打印出 Maven 搜索器所解析出来的构件信息.
2022-07-16 20:51:06 +08:00
93b9c6b727
refactor(launch): 统一代理的使用.
之前的版本中, 如果未指定 Maven 仓库的独立代理配置, 同时 Bot 拥有独立代理配置的情况下, Aether 将不会使用 Bot
的独立代理配置, 这样弄比较乱, 因此统一代理配置的使用顺序:
- 如果配置中包括了代理配置, 则优先使用独立代理配置;
- 如果不包括独立代理配置, 则使用关联 Bot 的独立代理配置;
- 如果关联 Bot 没有独立代理配置, 则使用 AppConfig 中的全局配置(如无配置则直连访问).
2022-07-16 20:46:15 +08:00
a8a0a9576f
build(dependencies): 更新 TelegramBots 依赖项的版本 (6.0.1 -> 6.1.0)
更新版本将有利于开发者和用户使用新的功能.
2022-07-16 20:30:22 +08:00
e8711e9974
refactor(meta): 为 ProxyConfig 覆盖 toString 方法.
覆盖 toString 方法后, 可以输出易懂的代理信息(我担心按照 data class 的格式输出, 用户可能看不懂).
2022-07-16 20:26:45 +08:00
93685e9440
test(config): 优化单元测试.
将 AppPaths 的单元测试也覆盖了, 直接方便了.
2022-07-12 01:29:19 +08:00
92b7e84b3a
test(config): 补充相关的单元测试.
经检查, 已确定完全覆盖代码, 为完成单元测试的编写, 稍微改了一下 AppPaths 的代码, 不会有影响的 :P
2022-07-12 01:20:53 +08:00
8c4e48e3eb
refactor(launch): 更改初始化配置中, 退出进程的时机.
为了能在单元测试中检查 initialFiles 是否正常, 故将 exitProcess 移到 main 方法中, 方便进行测试.
2022-07-12 00:27:18 +08:00
7f7b2b8895
build(meta): 调整部分依赖的引入范围.
将 Aether-api 和 telegrambots-meta 的引入范围由 implementation 改为 api,
方便依赖的其他项目使用.
2022-07-11 23:58:22 +08:00
441991b705
docs(extension): 补充部分扩展组件的 KDoc.
补充部分方法的文档, 不过文档内容嘛...有待加强.
2022-07-09 01:20:57 +08:00
51d036c4c6
feat(launch): 延后 BotConfig 的反序列化时机.
通过将 BotConfig 的反序列化时机延后到启动机器人的时候, 可以避免因某个机器人配置错误导致所有机器人都无法启动的问题.
注意, 语法错误还是会在启动时报错, 只是说部分序列化器会检查字段值是否有误, 通过延后反序列化来防止全反序列化的时候一个配置炸了影响全部而已.
2022-07-04 16:40:17 +08:00
3c54c33364
fix(config): 修复因正则表达式错误导致的 Token 检查失败.
由于表达式中限定的 BotId 为 Int 范围, 而目前的 TelegramUserId 已经扩展到 Long 了, 所以新的 Bot 是无法通过检查的, 已修正表达式问题.
2022-07-04 16:26:01 +08:00
43dd0e7bea
docs(meta): 加一个 Readme.
加一个文档来稍微说明一下这个模块的用途.
2022-07-03 02:50:32 +08:00
c144755913
feat(config): 增加 BotAccountSerializer, 主要用于检查字段值.
增加 BotAccount 的序列化器, 便于检查有关字段的值是否有效.
2022-07-03 02:32:37 +08:00
9ed55204c0
refactor(config): 调整序列化工具类, 便于进行测试.
修正序列化工具类的类名, 并调整访问权为 internal.
同时将 `checkJsonKey` 改成更方便的 `JsonObject.getPrimitiveValueOrThrow`.
2022-07-03 01:35:23 +08:00
9b7fc30512
fix(config): 修复因使用了错误的 Gson 对象而导致的配置初始化警告.
导致的原因是在初始化 app.json 时错误的使用了 botConfigGson, 而 botConfigGson 未配置用于 MetricsServer 的 UsernameAuthenticator 序列化器, 导致在初始化配置文件中序列化 AppConfig 时, Gson 会反射调用 BasicAuthenticator, 导致被 Java 模块系统拦截并报错, 现已修复该问题.
2022-07-02 22:01:05 +08:00
27dc26160d
refactor(config): 对配置文件的 AppPath 对象更名.
先前为确保后续可以增加指定配置文件路径的功能, 在命名上标记的 DEFAULT 在现在已经不符合实际意义了, 故将 DEFAULT 前缀移除.
2022-06-30 00:15:07 +08:00
ae411ce829
refactor(metrics): 调整 MetricsHttpServer 注册关闭钩子的时机.
将关闭钩子的时机调整到 main 方法中, 可以减少多余的钩子注册(比如测试时无需注册钩子, 却还是注册了).
2022-06-29 03:06:15 +08:00
1afe0f07a8
perf(extension): 优化 printExtensionFileConflictError 日志输出.
Kotlin-logging 在日志输出方法中做了检查, 如果级别未开启则不会调用方法获取日志内容,
故将内容构造部分移入 error 代码块以避免无意义的生成日志内容.
2022-06-29 03:03:16 +08:00
43 changed files with 1941 additions and 425 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
**/
!scalabot-app/build/install/

33
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,33 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "daily"
# - package-ecosystem: "gradle"
# directory: "/scalabot-app"
# schedule:
# interval: "weekly"
# - package-ecosystem: "gradle"
# directory: "/scalabot-meta"
# schedule:
# interval: "weekly"
# - package-ecosystem: "gradle"
# directory: "/scalabot-extension"
# schedule:
# interval: "weekly"
# - package-ecosystem: "gradle"
# directory: "/scalabot-ext-example"
# schedule:
# interval: "weekly"

View File

@ -0,0 +1,33 @@
name: Binary compatibility verification (for API)
on:
push:
paths:
- 'scalabot-meta/**'
- 'scalabot-extension/**'
pull_request:
paths:
- 'scalabot-meta/**'
- 'scalabot-extension/**'
permissions:
contents: read
jobs:
apiCompatibilityCheck:
timeout-minutes: 8
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt-hotspot'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build and run binary compatibility verification
run: ./gradlew apiCheck

View File

@ -18,17 +18,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '17'
distribution: 'adopt-hotspot'
cache: 'gradle'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build and test
uses: gradle/gradle-build-action@v2.2.1
with:
gradle-version: 'wrapper'
arguments: test
run: ./gradlew clean test

62
.github/workflows/create-release.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: Create release draft
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+*'
# 该 Action 有以下步骤:
# 1. 拉取并构建代码, 然后生成 Application 发行包;
# 2. 创建 Release, 并标记为 Draft(草稿);
# 3. 上传 Application 发行包;
permissions:
contents: write
jobs:
create-release:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# 创建更新日志.
- name: 'Get Previous tag'
id: previous-tag
uses: younited/get-previous-tag-action@v1.1.0
with:
match: "v*.*.*"
- name: Set up Python 3
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install Commitizen
run: pip install -U commitizen
- name: Create Change log
run: cz ch --start-rev ${{ steps.previous-tag.outputs.previous-tag }} --file-name ${{ github.workspace }}/CURRENT_CHANGELOG.md
# 开始构建项目.
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt-hotspot'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build and test
run: ./gradlew clean test assembleDist
# 创建新的发行版本
- name: Create Release
uses: softprops/action-gh-release@v2
with:
draft: true
body_path: ${{ github.workspace }}/CURRENT_CHANGELOG.md
files: |
*/build/distributions/*
*/build/libs/*

View File

@ -1,10 +0,0 @@
name: "Validate Gradle Wrapper"
on: [push, pull_request]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1

46
.github/workflows/publish-artifacts.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: Publish artifacts
on:
release:
types:
- published
env:
IMAGE_NAME: lamgc/scalabot
jobs:
publish-container-image:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt-hotspot'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build and test
run: ./gradlew clean test installDist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push container image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ env.IMAGE_NAME }}:latest, ${{ env.IMAGE_NAME }}:${{ github.ref_name }}
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@ -0,0 +1,46 @@
name: Build development version container image
on:
push:
branches:
- "main"
permissions:
contents: read
jobs:
build:
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'adopt-hotspot'
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build project and install Distribution package
run: ./gradlew clean test installDist
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push container image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: lamgc/scalabot:dev
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM eclipse-temurin:21-jdk-alpine
ENV BOT_DATA_PATH /scalabot/data/
WORKDIR /scalabot/run/
CMD ["/scalabot/app/bin/scalabot-app"]
COPY scalabot-app/build/install/scalabot-app/ /scalabot/app/

View File

@ -1,6 +1,7 @@
plugins {
kotlin("jvm") version "1.6.10" apply false
id("org.jetbrains.kotlinx.kover") version "0.5.1" apply false
kotlin("jvm") version "2.1.0" apply false
id("org.jetbrains.kotlinx.kover") version "0.8.3" apply false
id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.16.3" apply false
}
allprojects {
@ -12,5 +13,5 @@ allprojects {
}
group = "net.lamgc"
version = "0.4.0"
version = "0.8.0-1"
}

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

10
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright ? 2015-2021 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -32,10 +32,10 @@
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?,
# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?;
# * compound commands having a testable exit status, especially ?case?;
# * various built-in commands including ?command?, ?set?, and ?ulimit?.
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#

View File

@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
@ -10,9 +11,9 @@ dependencies {
implementation(project(":scalabot-meta"))
implementation(project(":scalabot-extension"))
implementation("org.slf4j:slf4j-api:1.7.36")
implementation("io.github.microutils:kotlin-logging:2.1.23")
implementation("ch.qos.logback:logback-classic:1.2.11")
implementation("org.slf4j:slf4j-api:2.0.11")
implementation("io.github.microutils:kotlin-logging:3.0.5")
implementation("ch.qos.logback:logback-classic:1.5.12")
val aetherVersion = "1.1.0"
implementation("org.eclipse.aether:aether-api:$aetherVersion")
@ -22,31 +23,35 @@ dependencies {
implementation("org.eclipse.aether:aether-transport-http:$aetherVersion")
implementation("org.eclipse.aether:aether-connector-basic:$aetherVersion")
implementation("org.apache.maven:maven-aether-provider:3.3.9")
implementation("org.codehaus.plexus:plexus-utils:3.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.6.20")
implementation("com.google.code.gson:gson:2.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
implementation("org.jetbrains.kotlin:kotlin-reflect:2.1.0")
implementation("com.google.code.gson:gson:2.11.0")
implementation("org.jdom:jdom2:2.0.6.1")
implementation("org.telegram:telegrambots-abilities:6.0.1")
implementation("org.telegram:telegrambots:6.0.1")
implementation("org.telegram:telegrambots-abilities:8.0.0")
implementation("org.telegram:telegrambots-longpolling:8.0.0")
implementation("org.telegram:telegrambots-client:8.0.0")
implementation("io.prometheus:simpleclient:0.15.0")
implementation("io.prometheus:simpleclient_httpserver:0.15.0")
implementation("io.prometheus:simpleclient:0.16.0")
implementation("io.prometheus:simpleclient_httpserver:0.16.0")
testImplementation(kotlin("test"))
testImplementation("io.mockk:mockk:1.12.4")
testImplementation("io.mockk:mockk:1.13.13")
testImplementation("com.github.stefanbirkner:system-lambda:1.2.1")
}
tasks.test {
useJUnitPlatform()
jvmArgs("--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED")
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
compilerOptions {
jvmTarget = JvmTarget.JVM_17
}
}
application {
@ -56,3 +61,8 @@ application {
tasks.jar.configure {
exclude("**/logback-test.xml")
}
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}

View File

@ -3,7 +3,7 @@ package net.lamgc.scalabot
import ch.qos.logback.core.PropertyDefinerBase
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import com.google.gson.JsonArray
import mu.KotlinLogging
import net.lamgc.scalabot.config.*
import net.lamgc.scalabot.config.serializer.*
@ -12,23 +12,24 @@ import org.eclipse.aether.repository.Authentication
import org.eclipse.aether.repository.Proxy
import org.eclipse.aether.repository.RemoteRepository
import org.eclipse.aether.repository.RepositoryPolicy
import org.telegram.telegrambots.bots.DefaultBotOptions
import org.slf4j.event.Level
import java.io.File
import java.net.URL
import java.nio.charset.StandardCharsets
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import kotlin.system.exitProcess
import java.util.function.Supplier
import kotlin.reflect.KProperty
private val log = KotlinLogging.logger { }
internal fun ProxyType.toTelegramBotsType(): DefaultBotOptions.ProxyType {
internal fun ProxyType.toJavaProxyType(): java.net.Proxy.Type? {
return when (this) {
ProxyType.NO_PROXY -> DefaultBotOptions.ProxyType.NO_PROXY
ProxyType.HTTP -> DefaultBotOptions.ProxyType.HTTP
ProxyType.HTTPS -> DefaultBotOptions.ProxyType.HTTP
ProxyType.SOCKS4 -> DefaultBotOptions.ProxyType.SOCKS4
ProxyType.SOCKS5 -> DefaultBotOptions.ProxyType.SOCKS5
ProxyType.NO_PROXY -> null
ProxyType.HTTP -> java.net.Proxy.Type.HTTP
ProxyType.HTTPS -> java.net.Proxy.Type.HTTP
ProxyType.SOCKS4 -> java.net.Proxy.Type.SOCKS
ProxyType.SOCKS5 -> java.net.Proxy.Type.SOCKS
}
}
@ -41,13 +42,32 @@ internal fun ProxyConfig.toAetherProxy(): Proxy? {
return Proxy(typeStr, host, port)
}
internal fun MavenRepositoryConfig.toRemoteRepository(proxyConfig: ProxyConfig): RemoteRepository {
val builder =
RemoteRepository.Builder(id ?: createDefaultRepositoryId(), checkRepositoryLayout(layout), url.toString())
internal fun MavenRepositoryConfig.toRemoteRepository(proxyConfig: ProxyConfig? = null): RemoteRepository {
val repositoryId = if (id == null) {
val generatedRepoId = createDefaultRepositoryId()
log.debug { "仓库 Url `$url` 未设置仓库 Id, 已分配缺省 Id: $generatedRepoId" }
generatedRepoId
} else if ("local".contentEquals(id, ignoreCase = true)) {
val generatedRepoId = createDefaultRepositoryId()
log.debug { "仓库 Url `$url` 不允许使用 `local` 作为仓库 Id, 已分配缺省 Id: $generatedRepoId" }
generatedRepoId
} else {
id
}
val builder = RemoteRepository.Builder(repositoryId, checkRepositoryLayout(layout), url.toString())
if (proxy != null) {
builder.setProxy(proxy)
} else if (proxyConfig.type == ProxyType.HTTP) {
val selfProxy = proxy!!
builder.setProxy(selfProxy)
log.debug { "仓库 $repositoryId 已使用独立的代理配置: ${selfProxy.type}://${selfProxy.host}:${selfProxy.port}" }
} else if (proxyConfig != null) {
if (proxyConfig.type in (ProxyType.HTTP..ProxyType.HTTPS)) {
builder.setProxy(proxyConfig.toAetherProxy())
log.debug { "仓库 $repositoryId 已使用 全局/Bot 代理配置: $proxyConfig" }
} else {
log.debug { "仓库 $repositoryId 不支持 全局/Bot 的代理配置: `$proxyConfig` (仅支持 HTTP 和 HTTPS)" }
}
} else {
log.debug { "仓库 $repositoryId 不使用代理." }
}
builder.setReleasePolicy(
@ -88,9 +108,9 @@ private fun createDefaultRepositoryId(): String {
* 必须提供 `pathSupplier` `fileSupplier` 其中一个, 才能正常提供路径.
*/
internal enum class AppPaths(
private val pathSupplier: () -> String = { fileSupplier.invoke().canonicalPath },
private val pathSupplier: PathSupplier,
private val initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer,
private val fileSupplier: () -> File = { File(pathSupplier()) }
private val fileSupplier: FileSupplier,
) {
/**
* 数据根目录.
@ -99,7 +119,7 @@ internal enum class AppPaths(
*
* 提示: 结尾不带 `/`.
*/
DATA_ROOT(fileSupplier = {
DATA_ROOT(fileSupplier = FileSupplier {
File(
System.getProperty(PathConst.PROP_DATA_PATH) ?: System.getenv(PathConst.ENV_DATA_PATH)
?: System.getProperty("user.dir") ?: "."
@ -111,10 +131,10 @@ internal enum class AppPaths(
}
}),
DEFAULT_CONFIG_APPLICATION({ "$DATA_ROOT/config.json" }, {
CONFIG_APPLICATION(PathSupplier { "$DATA_ROOT/config.json" }, {
if (!file.exists()) {
file.bufferedWriter(StandardCharsets.UTF_8).use {
GsonConst.botConfigGson.toJson(
GsonConst.appConfigGson.toJson(
AppConfig(
mavenRepositories = listOf(
MavenRepositoryConfig(
@ -127,7 +147,7 @@ internal enum class AppPaths(
}
}
}),
DEFAULT_CONFIG_BOT({ "$DATA_ROOT/bot.json" }, {
CONFIG_BOT(PathSupplier { "$DATA_ROOT/bot.json" }, {
if (!file.exists()) {
file.bufferedWriter(StandardCharsets.UTF_8).use {
GsonConst.botConfigGson.toJson(
@ -153,10 +173,25 @@ internal enum class AppPaths(
TEMP({ "$DATA_ROOT/tmp/" })
;
val file: File
get() = fileSupplier.invoke()
val path: String
get() = pathSupplier.invoke()
constructor(pathSupplier: PathSupplier, initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer) : this(
fileSupplier = FileSupplier { File(pathSupplier.path).canonicalFile },
pathSupplier = pathSupplier,
initializer = initializer
)
constructor(fileSupplier: FileSupplier, initializer: AppPaths.() -> Unit = AppPaths::defaultInitializer) : this(
fileSupplier = fileSupplier,
pathSupplier = PathSupplier { fileSupplier.file.canonicalPath },
initializer = initializer
)
constructor(pathSupplier: () -> String) : this(
fileSupplier = FileSupplier { File(pathSupplier.invoke()).canonicalFile },
pathSupplier = PathSupplier { pathSupplier.invoke() }
)
val file: File by fileSupplier
val path: String by pathSupplier
private val initialized = AtomicBoolean(false)
@ -168,15 +203,44 @@ internal enum class AppPaths(
}
}
/**
* 一个内部方法, 用于将 [initialized] 状态重置.
*
* 如果不重置该状态, 将使得单元测试无法让 AppPath 重新初始化文件.
*
* 警告: 该方法不应该被非测试代码调用.
*/
@Suppress("unused")
private fun reset() {
log.warn {
"初始化状态已重置: `${this.name}`, 如果在非测试环境中重置状态, 请报告该问题."
}
initialized.set(false)
}
override fun toString(): String {
return path
}
private object PathConst {
object PathConst {
const val PROP_DATA_PATH = "bot.path.data"
const val ENV_DATA_PATH = "BOT_DATA_PATH"
}
private class FileSupplier(private val supplier: Supplier<File>) {
operator fun getValue(appPaths: AppPaths, property: KProperty<*>): File = supplier.get()
val file: File
get() = supplier.get()
}
private class PathSupplier(private val supplier: Supplier<String>) {
operator fun getValue(appPaths: AppPaths, property: KProperty<*>): String = supplier.get()
val path: String
get() = supplier.get()
}
}
/**
@ -188,8 +252,37 @@ internal class LogDirectorySupplier : PropertyDefinerBase() {
}
}
internal class LogLevelSupplier : PropertyDefinerBase() {
override fun getPropertyValue(): String {
val property = System.getProperty("scalabot.log.level", System.getenv("BOT_LOG_LEVEL"))
val level = if (property != null) {
try {
Level.valueOf(property.uppercase())
} catch (e: IllegalArgumentException) {
addWarn("Invalid log level: `$property`, the log will be output using the Info log level.")
Level.INFO
}
} else {
Level.INFO
}
return level.name
}
}
internal class NetworkVerboseLogSupplier : PropertyDefinerBase() {
override fun getPropertyValue(): String {
val propertyValue = System.getProperty("scalabot.log.network.verbose", "false")
return if (propertyValue.toBoolean()) {
"DEBUG"
} else {
"INFO"
}
}
}
internal object Const {
val config = loadAppConfig()
const val METRICS_NAMESPACE = "scalabot"
}
private fun AppPaths.defaultInitializer() {
@ -207,22 +300,28 @@ private fun AppPaths.defaultInitializer() {
}
}
internal fun initialFiles() {
val configFilesNotInitialized = !AppPaths.DEFAULT_CONFIG_APPLICATION.file.exists()
&& !AppPaths.DEFAULT_CONFIG_BOT.file.exists()
/**
* 执行 AppPaths 所有项目的初始化, 并检查是否停止运行, 让用户编辑配置.
*
* @return 如果需要让用户编辑配置, 则返回 `true`.
*/
internal fun initialFiles(): Boolean {
val configFilesNotInitialized = !AppPaths.CONFIG_APPLICATION.file.exists()
&& !AppPaths.CONFIG_BOT.file.exists()
for (path in AppPaths.values()) {
for (path in AppPaths.entries) {
path.initial()
}
if (configFilesNotInitialized) {
log.warn { "配置文件已初始化, 请根据需要修改配置文件后重新启动本程序." }
exitProcess(1)
return true
}
return false
}
private object GsonConst {
val baseGson: Gson = GsonBuilder()
internal object GsonConst {
private val baseGson: Gson = GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.create()
@ -238,10 +337,11 @@ private object GsonConst {
.registerTypeAdapter(ProxyType::class.java, ProxyTypeSerializer)
.registerTypeAdapter(BotConfig::class.java, BotConfigSerializer)
.registerTypeAdapter(Artifact::class.java, ArtifactSerializer)
.registerTypeAdapter(BotAccount::class.java, BotAccountSerializer)
.create()
}
internal fun loadAppConfig(configFile: File = AppPaths.DEFAULT_CONFIG_APPLICATION.file): AppConfig {
internal fun loadAppConfig(configFile: File = AppPaths.CONFIG_APPLICATION.file): AppConfig {
try {
configFile.bufferedReader(StandardCharsets.UTF_8).use {
return GsonConst.appConfigGson.fromJson(it, AppConfig::class.java)!!
@ -252,10 +352,10 @@ internal fun loadAppConfig(configFile: File = AppPaths.DEFAULT_CONFIG_APPLICATIO
}
}
internal fun loadBotConfig(botConfigFile: File = AppPaths.DEFAULT_CONFIG_BOT.file): Set<BotConfig>? {
internal fun loadBotConfigJson(botConfigFile: File = AppPaths.CONFIG_BOT.file): JsonArray? {
try {
botConfigFile.bufferedReader(StandardCharsets.UTF_8).use {
return GsonConst.botConfigGson.fromJson(it, object : TypeToken<Set<BotConfig>>() {}.type)!!
return GsonConst.botConfigGson.fromJson(it, JsonArray::class.java)!!
}
} catch (e: Exception) {
log.error(e) { "读取 Bot 配置文件 (bot.json) 时发生错误, 请检查配置格式是否正确." }

View File

@ -1,20 +1,22 @@
package net.lamgc.scalabot
import com.google.gson.JsonParseException
import io.prometheus.client.exporter.HTTPServer
import kotlinx.coroutines.runBlocking
import mu.KotlinLogging
import net.lamgc.scalabot.config.AppConfig
import net.lamgc.scalabot.config.BotConfig
import net.lamgc.scalabot.config.MetricsConfig
import net.lamgc.scalabot.config.ProxyType
import net.lamgc.scalabot.config.*
import net.lamgc.scalabot.util.registerShutdownHook
import okhttp3.OkHttpClient
import org.eclipse.aether.repository.LocalRepository
import org.telegram.telegrambots.bots.DefaultBotOptions
import org.telegram.telegrambots.meta.TelegramBotsApi
import org.telegram.telegrambots.meta.generics.BotSession
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession
import org.telegram.telegrambots.client.okhttp.OkHttpTelegramClient
import org.telegram.telegrambots.longpolling.BotSession
import org.telegram.telegrambots.longpolling.TelegramBotsLongPollingApplication
import org.telegram.telegrambots.meta.api.methods.GetMe
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException
import java.io.File
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Proxy
import java.nio.file.attribute.PosixFilePermission
import java.nio.file.attribute.PosixFilePermissions
import kotlin.io.path.createDirectories
@ -28,12 +30,15 @@ private val log = KotlinLogging.logger { }
fun main(args: Array<String>): Unit = runBlocking {
log.info { "ScalaBot 正在启动中..." }
log.info { "数据目录: ${AppPaths.DATA_ROOT}" }
log.debug { "Kotlin: ${KotlinVersion.CURRENT}, JVM: ${Runtime.version()}" }
log.debug { "启动参数: ${args.joinToString(prefix = "[", postfix = "]")}" }
initialFiles()
if (initialFiles()) {
exitProcess(1)
}
val launcher = Launcher()
.registerShutdownHook()
startMetricsServer()
startMetricsServer()?.registerShutdownHook()
if (!launcher.launch()) {
exitProcess(1)
}
@ -57,28 +62,28 @@ internal fun startMetricsServer(config: MetricsConfig = Const.config.metrics): H
val httpServer = builder
.build()
.registerShutdownHook()
log.info { "运行指标服务器已启动. (Port: ${httpServer.port})" }
return httpServer
}
internal class Launcher(private val config: AppConfig = Const.config) : AutoCloseable {
internal class Launcher(
private val config: AppConfig = Const.config,
private val configFile: File = AppPaths.CONFIG_APPLICATION.file,
) : AutoCloseable {
companion object {
@JvmStatic
private val log = KotlinLogging.logger { }
}
private val botApi = TelegramBotsApi(DefaultBotSession::class.java)
private val botApi = TelegramBotsLongPollingApplication()
private val botSessionMap = mutableMapOf<ScalaBot, BotSession>()
private val mavenLocalRepository = getMavenLocalRepository()
private fun getMavenLocalRepository(): LocalRepository {
val localPath =
if (config.mavenLocalRepository != null && config.mavenLocalRepository!!.isNotEmpty()) {
val repoPath = AppPaths.DATA_ROOT.file.toPath()
.resolve(config.mavenLocalRepository!!)
.apply {
val repoPath = configFile.toPath().resolve(config.mavenLocalRepository!!).apply {
if (!exists()) {
if (!parent.isWritable() || !parent.isReadable()) {
throw IOException("Unable to read and write the directory where Maven repository is located.")
@ -111,22 +116,47 @@ internal class Launcher(private val config: AppConfig = Const.config) : AutoClos
@Synchronized
fun launch(): Boolean {
val botConfigs = loadBotConfig() ?: return false
if (botConfigs.isEmpty()) {
val botConfigs = loadBotConfigJson() ?: return false
if (botConfigs.isEmpty) {
log.warn { "尚未配置任何机器人, 请先配置机器人后再启动本程序." }
return false
} else if (botConfigs.none { it.enabled }) {
log.warn { "配置文件中没有已启用的机器人, 请至少启用一个机器人." }
return false
}
for (botConfig in botConfigs) {
var launchedCounts = 0
for (botConfigJson in botConfigs) {
val botConfig = try {
GsonConst.botConfigGson.fromJson(botConfigJson, BotConfig::class.java)
} catch (e: JsonParseException) {
val botName = try {
botConfigJson.asJsonObject.get("account")?.asJsonObject?.get("name")?.asString ?: "Unknown"
} catch (e: Exception) {
"Unknown"
}
log.error(e) { "机器人 `$botName` 配置有误, 跳过该机器人的启动." }
continue
}
try {
launchBot(botConfig)
launchedCounts++
} catch (e: Exception) {
if (e is TelegramApiRequestException && e.errorCode == 401) {
log.error { "机器人 `${botConfig.account.name}` 的 Bot Token 无效, 请检查配置: [${e.errorCode}] ${e.apiResponse}" }
} else {
log.error(e) { "机器人 `${botConfig.account.name}` 启动时发生错误." }
}
}
return true
}
botApi.start()
botApi.registerShutdownHook()
return if (launchedCounts != 0) {
log.info { "已启动 $launchedCounts 个机器人." }
true
} else {
log.warn { "未启动任何机器人, 请检查配置并至少启用一个机器人." }
false
}
}
private fun launchBot(botConfig: BotConfig) {
@ -135,34 +165,38 @@ internal class Launcher(private val config: AppConfig = Const.config) : AutoClos
return
}
log.info { "正在启动机器人 `${botConfig.account.name}`..." }
val botOption = DefaultBotOptions().apply {
val proxyConfig =
if (botConfig.proxy.type != ProxyType.NO_PROXY) {
log.debug { "[Bot ${botConfig.account.name}] 使用独立代理: ${botConfig.proxy.type}" }
botConfig.proxy
} else if (config.proxy.type != ProxyType.NO_PROXY) {
log.debug { "[Bot ${botConfig.account.name}] 使用全局代理: ${botConfig.proxy.type}" }
config.proxy
} else {
null
}
if (proxyConfig != null) {
proxyType = proxyConfig.type.toTelegramBotsType()
proxyHost = config.proxy.host
proxyPort = config.proxy.port
log.debug { "机器人 `${botConfig.account.name}` 已启用代理配置: $proxyConfig" }
log.debug { "[Bot ${botConfig.account.name}] 不使用代理." }
ProxyConfig(type = ProxyType.NO_PROXY)
}
baseUrl = botConfig.baseApiUrl
val okhttpClientBuilder = OkHttpClient.Builder()
if (proxyConfig.type != ProxyType.NO_PROXY) {
val proxyType = proxyConfig.type.toJavaProxyType()
val proxyAddress = InetSocketAddress.createUnresolved(proxyConfig.host, proxyConfig.port)
okhttpClientBuilder.proxy(Proxy(proxyType, proxyAddress))
}
val account = botConfig.account
val telegramClient =
OkHttpTelegramClient(okhttpClientBuilder.build(), account.token, botConfig.getBaseApiTelegramUrl())
val remoteRepositories = config.mavenRepositories
.map { it.toRemoteRepository(config.proxy) }
.map { it.toRemoteRepository(proxyConfig) }
.toMutableList().apply {
if (this.none {
it.url == MavenRepositoryExtensionFinder.MAVEN_CENTRAL_URL
|| it.url == MavenRepositoryExtensionFinder.MAVEN_CENTRAL_URL.trimEnd('/')
}) {
add(MavenRepositoryExtensionFinder.getMavenCentralRepository(proxy = config.proxy.toAetherProxy()))
add(MavenRepositoryExtensionFinder.getMavenCentralRepository(proxy = proxyConfig.toAetherProxy()))
}
}.toList()
val extensionPackageFinders = setOf(
@ -175,11 +209,15 @@ internal class Launcher(private val config: AppConfig = Const.config) : AutoClos
val bot = ScalaBot(
BotDBMaker.getBotDbInstance(account),
botOption,
telegramClient,
extensionPackageFinders,
botConfig
)
botSessionMap[bot] = botApi.registerBot(bot)
val botUser = bot.telegramClient.execute(GetMe())
log.debug { "已验证 Bot Token 有效性, Bot Username: ${botUser.userName}" }
botSessionMap[bot] = botApi.registerBot(botConfig.account.token, bot)
log.info { "机器人 `${bot.botUsername}` 已启动." }
if (botConfig.autoUpdateCommandList) {

View File

@ -7,8 +7,8 @@ import net.lamgc.scalabot.util.toHexString
import org.mapdb.DB
import org.mapdb.DBException
import org.mapdb.DBMaker
import org.telegram.abilitybots.api.db.DBContext
import org.telegram.abilitybots.api.db.MapDBContext
import org.telegram.telegrambots.abilitybots.api.db.DBContext
import org.telegram.telegrambots.abilitybots.api.db.MapDBContext
import java.io.File
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
@ -157,7 +157,6 @@ private abstract class FileDbAdapter(
val oldFile = oldDbAdapter.getBotDbFile(botAccount)
val newFile = getBotDbFile(botAccount)
try {
@Suppress("UnstableApiUsage")
Files.copy(oldFile, newFile)
} catch (e: Exception) {
if (newFile.exists()) {

View File

@ -1,10 +1,11 @@
package net.lamgc.scalabot
import mu.KotlinLogging
import net.lamgc.scalabot.extension.BotExtensionCreateOptions
import net.lamgc.scalabot.extension.BotExtensionFactory
import net.lamgc.scalabot.util.getPriority
import org.eclipse.aether.artifact.Artifact
import org.telegram.abilitybots.api.util.AbilityExtension
import org.telegram.telegrambots.abilitybots.api.util.AbilityExtension
import java.io.File
import java.io.FileNotFoundException
import java.net.URL
@ -14,6 +15,18 @@ import java.nio.charset.StandardCharsets
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
/**
* 扩展加载器.
*
* 扩展加载器并非负责加载扩展的 Class, 而是委派搜索器发现并获取扩展, 然后加载扩展实例.
*
* 注意, 扩展加载器将内置两个 Finder: [FileNameFinder] [MavenMetaInformationFinder].
*
* @param bot 扩展加载器所负责的 ScalaBot 实例.
* @param extensionsDataFolder 提供给扩展用于数据存储的根目录(实际目录为 `{root}/{group...}/{artifact}`).
* @param extensionsPath 提供给 Finder 用于搜索扩展的本地扩展包存放路径.
* @param extensionFinders 加载器所使用的搜索器集合. 加载扩展时将使用所提供的的加载器.
*/
internal class ExtensionLoader(
private val bot: ScalaBot,
private val extensionsDataFolder: File = AppPaths.DATA_EXTENSIONS.file,
@ -27,6 +40,13 @@ internal class ExtensionLoader(
MavenMetaInformationFinder
).apply { addAll(extensionFinders) }.toSet()
/**
* 加载扩展, 并返回扩展项.
*
* 调用本方法后, 将会指派提供的 Finder 搜索 ScalaBot 配置的扩展包.
*
* @return 返回存放了所有已加载扩展项的 Set. 可通过 [LoadedExtensionEntry] 获取扩展的有关信息.
*/
fun getExtensions(): Set<LoadedExtensionEntry> {
val extensionEntries = mutableSetOf<LoadedExtensionEntry>()
for (extensionArtifact in bot.extensions) {
@ -52,6 +72,17 @@ internal class ExtensionLoader(
/**
* 检查是否发生冲突.
*
* 扩展包冲突有两种情况:
* 1. 有多个同为最高优先级的搜索器搜索到了扩展包.
* 2. 唯一的最高优先级搜索器搜索到了多个扩展包.
*
* 扩展包冲突指的是**有多个具有相同构件坐标的扩展包被搜索到**,
* 如果不顾扩展包冲突直接加载的话, 将会出现安全隐患,
* 因此在加载器发现冲突的情况下将输出相关信息, 提示用户进行排查.
*
* @param foundResult 扩展包搜索结果.
*
* @return 如果出现冲突, 返回 `true`.
*/
private fun checkConflict(foundResult: Map<ExtensionPackageFinder, Set<FoundExtensionPackage>>): Boolean {
@ -68,6 +99,9 @@ internal class ExtensionLoader(
}
}
/**
* 从结果中过滤出由最高优先级的搜索器搜索到的扩展包.
*/
private fun filterHighPriorityResult(foundResult: Map<ExtensionPackageFinder, Set<FoundExtensionPackage>>)
: Map<ExtensionPackageFinder, Set<FoundExtensionPackage>> {
val finders: List<ExtensionPackageFinder> = foundResult.keys
@ -89,7 +123,13 @@ internal class ExtensionLoader(
for (factory in extClassLoader.serviceLoader) {
try {
val extension =
factory.createExtensionInstance(bot, getExtensionDataFolder(extensionArtifact))
factory.createExtensionInstance(
bot, getExtensionDataFolder(extensionArtifact),
BotExtensionCreateOptions(
bot.accountId,
bot.botConfig.proxy.copy()
)
)
if (extension == null) {
log.debug { "Factory ${factory::class.java} 创建插件时返回了 null, 已跳过. (BotName: ${bot.botUsername})" }
continue
@ -102,6 +142,11 @@ internal class ExtensionLoader(
return factories.toSet()
}
/**
* 只是用来统计扩展包搜索结果的数量而已.
*
* @return 返回扩展包的数量.
*/
private fun allFoundedPackageNumber(filesMap: Map<ExtensionPackageFinder, Set<FoundExtensionPackage>>): Int {
var number = 0
for (files in filesMap.values) {
@ -110,6 +155,14 @@ internal class ExtensionLoader(
return number
}
/**
* 搜索指定构件坐标的依赖包.
*
* 搜索扩展包将根据搜索器优先级从高到低依次搜索, 当某一个优先级的搜索器搜到扩展包后将停止搜索.
* 可以根据不同优先级的搜索器, 配置扩展包的主用和备用文件.
*
* @return 返回各个搜索器返回的搜索结果.
*/
private fun findExtensionPackage(
extensionArtifact: Artifact,
): Map<ExtensionPackageFinder, Set<FoundExtensionPackage>> {
@ -138,13 +191,21 @@ internal class ExtensionLoader(
return result
}
/**
* 检查扩展包搜索器是否设置了 [FinderRules] 注解.
* @return 如果已设置注解, 则返回 `true`.
*/
private fun checkExtensionPackageFinder(finder: ExtensionPackageFinder): Boolean =
finder::class.java.getDeclaredAnnotation(FinderRules::class.java) != null
/**
* 在日志中输出有关扩展包冲突的错误信息.
*/
private fun printExtensionFileConflictError(
extensionArtifact: Artifact,
foundResult: Map<ExtensionPackageFinder, Set<FoundExtensionPackage>>
) {
log.error {
val errMessage = StringBuilder(
"""
[Bot ${bot.botUsername}] 扩展包 $extensionArtifact 存在多个文件, 为防止安全问题, 已禁止加载该扩展包:
@ -160,9 +221,15 @@ internal class ExtensionLoader(
.append(URLDecoder.decode(file.getRawUrl().toString(), StandardCharsets.UTF_8)).append('\n')
}
}
log.error { errMessage }
errMessage
}
}
/**
* 创建扩展数据目录, 并返回 [File] 对象.
* @param extensionArtifact 扩展包构件坐标.
* @return 返回对应的数据存储目录.
*/
private fun getExtensionDataFolder(extensionArtifact: Artifact): File {
val dataFolder =
File(extensionsDataFolder, "${extensionArtifact.groupId}/${extensionArtifact.artifactId}")
@ -172,6 +239,12 @@ internal class ExtensionLoader(
return dataFolder
}
/**
* 已加载扩展项.
* @property extensionArtifact 扩展的构件坐标([Artifact]).
* @property factoryClass 扩展的工厂类.
* @property extension 扩展实例.
*/
data class LoadedExtensionEntry(
val extensionArtifact: Artifact,
val factoryClass: Class<out BotExtensionFactory>,
@ -181,6 +254,10 @@ internal class ExtensionLoader(
}
/**
* 扩展的类加载器清除器.
*
* 原计划是用来通过关闭 ClassLoader 来卸载扩展的, 但似乎并没有这么做.
*
* 该类为保留措施, 尚未启用.
*/
internal object ExtensionClassLoaderCleaner {
@ -257,7 +334,7 @@ internal interface ExtensionPackageFinder {
/**
* 已找到的扩展包信息.
* 通过实现该接口, 以寻找远端文件的 [ExtensionPackageFinder]
* 通过实现该接口, 以寻找远端文件的 [ExtensionPackageFinder];
* 可以在适当的时候将扩展包下载到本地, 而无需在搜索阶段下载扩展包.
*/
internal interface FoundExtensionPackage {
@ -296,6 +373,7 @@ private fun FoundExtensionPackage.createClassLoader(): ExtensionClassLoader =
* 已找到的扩展包文件.
* @param artifact 扩展包构件坐标.
* @param file 已找到的扩展包文件.
* @param finder 搜索到该扩展包的搜索器.
*/
internal class FileFoundExtensionPackage(
private val artifact: Artifact,
@ -342,14 +420,14 @@ internal class ExtensionClassLoader(urls: Array<URL>, dependencyLoader: ClassLoa
// 以免使用了不来自扩展包的机器人扩展.
override fun getResources(name: String?): Enumeration<URL> {
if (BotExtensionFactory::class.java.equals(name)) {
if ("META-INF/services/${BotExtensionFactory::class.java.name}" == name) {
return findResources(name)
}
return super.getResources(name)
}
override fun getResource(name: String?): URL? {
if (BotExtensionFactory::class.java.equals(name)) {
if ("META-INF/services/${BotExtensionFactory::class.java}" == name) {
return findResource(name)
}
return super.getResource(name)

View File

@ -26,6 +26,7 @@ import org.jdom2.input.SAXBuilder
import org.jdom2.xpath.XPathFactory
import java.io.File
import java.io.InputStream
import java.net.URI
import java.net.URL
import java.net.URLClassLoader
import java.util.*
@ -257,23 +258,25 @@ internal class MavenRepositoryExtensionFinder(
}
override fun findByArtifact(extensionArtifact: Artifact, extensionsPath: File): Set<FoundExtensionPackage> {
val repositories = repositorySystem.newResolutionRepositories(repoSystemSession, remoteRepositories).toList()
log.debug {
StringBuilder().apply {
append("构件 $extensionArtifact 将在以下仓库拉取: \n")
remoteRepositories.forEach {
append("\t- ${it}\n")
repositories.forEach {
append("\t- $it\n")
}
}
}
val extensionArtifactResult = repositorySystem.resolveArtifact(
repoSystemSession,
ArtifactRequest(
extensionArtifact,
repositorySystem.newResolutionRepositories(repoSystemSession, remoteRepositories),
repositories,
null
)
)
val extResolvedArtifact = extensionArtifactResult.artifact
val resolvedArtifact: Artifact? = extensionArtifactResult.artifact
if (!extensionArtifactResult.isResolved) {
if (extensionArtifactResult.isMissing) {
log.warn { "在指定的仓库中找不到构件: ${extensionArtifactResult.artifact}" }
@ -281,17 +284,26 @@ internal class MavenRepositoryExtensionFinder(
printArtifactResultExceptions(extensionArtifactResult.exceptions)
}
return emptySet()
} else if (resolvedArtifact == null) {
log.warn { "无法在指定的仓库中解析构件: $extensionArtifact" }
return emptySet()
}
log.info {
"已从 Maven 仓库 `${extensionArtifactResult.repository.id}` 中找到" +
"扩展包 `${resolvedArtifact.groupId}:${resolvedArtifact.artifactId}` " +
"版本号 `${resolvedArtifact.version}`."
}
val request = DependencyRequest(
CollectRequest(Dependency(extResolvedArtifact, null), remoteRepositories),
CollectRequest(Dependency(resolvedArtifact, null), repositories),
ScopeDependencyFilter(setOf("runtime", "compile", "provided"), null)
)
val dependencyResult = repositorySystem.resolveDependencies(repoSystemSession, request)
val dependencies = checkAndCollectDependencyArtifacts(extensionArtifact, dependencyResult.artifactResults)
?: return emptySet()
return setOf(MavenExtensionPackage(this, extResolvedArtifact, extensionArtifactResult.repository, dependencies))
return setOf(MavenExtensionPackage(this, resolvedArtifact, extensionArtifactResult.repository, dependencies))
}
private fun checkAndCollectDependencyArtifacts(
@ -385,7 +397,6 @@ internal class MavenRepositoryExtensionFinder(
/**
* Maven 中央仓库 Url.
*/
@Suppress("MemberVisibilityCanBePrivate")
const val MAVEN_CENTRAL_URL = "https://repo1.maven.org/maven2/"
/**
@ -455,17 +466,19 @@ internal class MavenRepositoryExtensionFinder(
throw IllegalArgumentException("Unsupported FoundExtensionPackage type: $foundExtensionPackage")
}
val urls = mutableSetOf<URL>()
val urls = mutableSetOf<URI>()
for (dependency in foundExtensionPackage.dependencies) {
val dependencyFile = dependency.file ?: continue
urls.add(dependencyFile.toURI().toURL())
urls.add(dependencyFile.toURI())
}
// 将依赖的 ClassLoader 与 ExtensionPackage 的 ClassLoader 分开
// 这么做可以防范依赖中隐藏的 SPI 注册, 避免安全隐患.
val dependenciesUrlArray = urls.toTypedArray()
val dependenciesClassLoader = URLClassLoader(dependenciesUrlArray)
val dependenciesClassLoader = URLClassLoader(
dependenciesUrlArray.map { it.toURL() }.toTypedArray()
)
return ExtensionClassLoader(
arrayOf(foundExtensionPackage.getPackageFile().toURI().toURL()),

View File

@ -6,43 +6,42 @@ import io.prometheus.client.Summary
import mu.KotlinLogging
import net.lamgc.scalabot.config.BotConfig
import org.eclipse.aether.artifact.Artifact
import org.telegram.abilitybots.api.bot.AbilityBot
import org.telegram.abilitybots.api.db.DBContext
import org.telegram.abilitybots.api.objects.Ability
import org.telegram.abilitybots.api.toggle.BareboneToggle
import org.telegram.abilitybots.api.toggle.DefaultToggle
import org.telegram.telegrambots.bots.DefaultBotOptions
import org.telegram.telegrambots.abilitybots.api.bot.AbilityBot
import org.telegram.telegrambots.abilitybots.api.db.DBContext
import org.telegram.telegrambots.abilitybots.api.objects.Ability
import org.telegram.telegrambots.abilitybots.api.toggle.BareboneToggle
import org.telegram.telegrambots.abilitybots.api.toggle.DefaultToggle
import org.telegram.telegrambots.meta.api.methods.commands.DeleteMyCommands
import org.telegram.telegrambots.meta.api.methods.commands.SetMyCommands
import org.telegram.telegrambots.meta.api.objects.Update
import org.telegram.telegrambots.meta.api.objects.commands.BotCommand
import org.telegram.telegrambots.meta.generics.TelegramClient
/**
* 可扩展 Bot.
* @property creatorId 机器人所有人的 Telegram 用户 Id. 可通过联系部分机器人来获取该信息.
* @property creatorId 机器人所有人的 Telegram 用户 ID. 可通过联系部分机器人来获取该信息.
* (e.g. [@userinfobot](http://t.me/userinfobot))
* @param db 机器人数据库对象. 用于状态机等用途.
* @param options AbilityBot 设置对象.
* @property extensions 扩展坐标集合.
*/
@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate")
internal class ScalaBot(
db: DBContext,
options: DefaultBotOptions,
client: TelegramClient,
extensionFinders: Set<ExtensionPackageFinder>,
botConfig: BotConfig,
private val creatorId: Long = botConfig.account.creatorId,
val botConfig: BotConfig,
val accountId: Long = botConfig.account.id,
private val creatorId: Long = botConfig.account.creatorId,
val extensions: Set<Artifact> = botConfig.extensions
) :
AbilityBot(
botConfig.account.token,
client,
botConfig.account.name,
db,
if (botConfig.disableBuiltInAbility)
BareboneToggle()
else
DefaultToggle(),
options
DefaultToggle()
) {
private val extensionLoader = ExtensionLoader(
@ -50,6 +49,8 @@ internal class ScalaBot(
extensionFinders = extensionFinders
)
private val accountIdString = accountId.toString()
init {
log.info { "[Bot $botUsername] 正在加载扩展..." }
val extensionEntries = extensionLoader.getExtensions()
@ -65,19 +66,19 @@ internal class ScalaBot(
override fun creatorId(): Long = creatorId
override fun onUpdateReceived(update: Update?) {
botUpdateCounter.labels(botUsername).inc()
botUpdateGauge.labels(botUsername).inc()
override fun consume(update: Update?) {
botUpdateCounter.labels(botUsername, accountIdString).inc()
botUpdateGauge.labels(botUsername, accountIdString).inc()
val timer = updateProcessTime.labels(botUsername).startTimer()
val timer = updateProcessTime.labels(botUsername, accountIdString).startTimer()
try {
super.onUpdateReceived(update)
super.consume(update)
} catch (e: Exception) {
exceptionHandlingCounter.labels(botUsername).inc()
exceptionHandlingCounter.labels(botUsername, accountIdString).inc()
throw e
} finally {
timer.observeDuration()
botUpdateGauge.labels(botUsername).dec()
botUpdateGauge.labels(botUsername, accountIdString).dec()
}
}
@ -90,11 +91,11 @@ internal class ScalaBot(
* @return 更新成功返回 `true`.
*/
fun updateCommandList(): Boolean {
if (abilities() == null) {
if (abilities == null) {
throw IllegalStateException("Abilities has not been initialized.")
}
val botCommands = abilities().values.map {
val botCommands = abilities.values.map {
val abilityInfo = if (it.info() == null || it.info().trim().isEmpty()) {
log.warn { "[Bot $botUsername] Ability `${it.name()}` 没有说明信息." }
"(The command has no description)"
@ -110,9 +111,10 @@ internal class ScalaBot(
return true
}
val setMyCommands = SetMyCommands()
setMyCommands.commands = botCommands
return execute(DeleteMyCommands()) && execute(setMyCommands)
val setMyCommands = SetMyCommands.builder()
.commands(botCommands)
.build()
return telegramClient.execute(DeleteMyCommands()) && telegramClient.execute(setMyCommands)
}
override fun onRegister() {
@ -120,10 +122,6 @@ internal class ScalaBot(
onlineBotGauge.inc()
}
override fun onClosing() {
onlineBotGauge.dec()
}
companion object {
@JvmStatic
private val log = KotlinLogging.logger { }
@ -134,7 +132,8 @@ internal class ScalaBot(
private val botUpdateCounter = Counter.build()
.name("updates_total")
.help("Total number of updates received by all bots.")
.labelNames("bot_name")
.labelNames("bot_name", "bot_id")
.namespace(Const.METRICS_NAMESPACE)
.subsystem("telegrambots")
.register()
@ -142,7 +141,8 @@ internal class ScalaBot(
private val botUpdateGauge = Gauge.build()
.name("updates_in_progress")
.help("Number of updates in process by all bots.")
.labelNames("bot_name")
.labelNames("bot_name", "bot_id")
.namespace(Const.METRICS_NAMESPACE)
.subsystem("telegrambots")
.register()
@ -150,6 +150,7 @@ internal class ScalaBot(
private val onlineBotGauge = Gauge.build()
.name("bots_online")
.help("Number of bots Online.")
.namespace(Const.METRICS_NAMESPACE)
.subsystem("telegrambots")
.register()
@ -161,7 +162,8 @@ internal class ScalaBot(
"so it may be different from the actual execution time of ability. " +
"It is not recommended to use it as the accurate execution time of ability)"
)
.labelNames("bot_name")
.labelNames("bot_name", "bot_id")
.namespace(Const.METRICS_NAMESPACE)
.subsystem("telegrambots")
.register()
@ -169,7 +171,8 @@ internal class ScalaBot(
private val exceptionHandlingCounter = Counter.build()
.name("updates_exception_handling")
.help("Number of exceptions during processing.")
.labelNames("bot_name")
.labelNames("bot_name", "bot_id")
.namespace(Const.METRICS_NAMESPACE)
.subsystem("telegrambots")
.register()
}

View File

@ -0,0 +1,29 @@
package net.lamgc.scalabot.util
import java.util.regex.Matcher
import java.util.regex.Pattern
object TelegramBotAccounts {
private val botTokenPattern: Pattern = Pattern.compile("([1-9]\\d+):([A-Za-z\\d_-]{35,})")
/**
* 获取 AbilityBot 的账户 Id.
*
*
* 账户 Id 来自于 botToken , token 的格式为 "{AccountId}:{Secret}".
*
* 账户 Id 的真实性与 botToken 的有效性有关, 本方法并不会确保 botToken 的有效性, 一般情况下也无需考虑 Id 的有效性,
* 如果有需要, 可尝试通过调用 [org.telegram.telegrambots.meta.api.methods.GetMe] 来确保 botToken 的有效性.
*
* @param botToken 要获取账户 Id botToken 字符串.
* @return 返回 AbilityBot 的账户 Id.
* @throws IllegalArgumentException AbilityBot botToken 格式错误时抛出该异常.
*/
fun getBotAccountId(botToken: String): Long {
val matcher: Matcher = botTokenPattern.matcher(botToken)
require(matcher.matches()) { "Invalid token format." }
return matcher.group(1).toLong()
}
}

View File

@ -74,7 +74,7 @@ fun <T : AutoCloseable> T.registerShutdownHook(): T {
private object UtilsInternal {
val autoCloseableSet = mutableSetOf<AutoCloseable>()
private val log = KotlinLogging.logger { }
private val log = KotlinLogging.logger(UtilsInternal::class.java.name)
init {
Runtime.getRuntime().addShutdownHook(Thread(this::doCloseResources, "Shutdown-AutoCloseable"))

View File

@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8" ?>
<included>
<define name="DATA_LOGS" class="net.lamgc.scalabot.LogDirectorySupplier"/>
<define name="LOG_LEVEL" class="net.lamgc.scalabot.LogLevelSupplier"/>
<define name="NETWORK_LOG_LEVEL" class="net.lamgc.scalabot.NetworkVerboseLogSupplier"/>
<appender name="STD_OUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
@ -24,7 +26,7 @@
<appender name="FILE_OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${DATA_LOGS}/latest.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>data/logs/%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<fileNamePattern>${DATA_LOGS}/%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>

View File

@ -1,16 +0,0 @@
<configuration scan="false" debug="false">
<include resource="base-logback.xml"/>
<logger name="org.apache.http" level="INFO"/>
<logger name="org.eclipse.aether.internal.impl.DefaultTransporterProvider" level="INFO"/>
<logger name="org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider" level="INFO"/>
<logger name="org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager" level="INFO"/>
<logger name="org.telegram.telegrambots.facilities.proxysocketfactorys" level="INFO"/>
<logger name="org.eclipse.aether.internal.impl.DefaultUpdateCheckManager" level="INFO"/>
<root level="DEBUG">
<appender-ref ref="FILE_OUT"/>
<appender-ref ref="STD_ERR"/>
<appender-ref ref="STD_OUT"/>
</root>
</configuration>

View File

@ -1,7 +1,14 @@
<configuration scan="false" debug="false">
<include resource="base-logback.xml"/>
<root level="INFO">
<logger name="org.apache.http" level="${NETWORK_LOG_LEVEL}"/>
<logger name="org.eclipse.aether.internal.impl.DefaultTransporterProvider" level="${NETWORK_LOG_LEVEL}"/>
<logger name="org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider" level="${NETWORK_LOG_LEVEL}"/>
<logger name="org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager" level="${NETWORK_LOG_LEVEL}"/>
<logger name="org.telegram.telegrambots.facilities.proxysocketfactorys" level="${NETWORK_LOG_LEVEL}"/>
<logger name="org.eclipse.aether.internal.impl.DefaultUpdateCheckManager" level="${NETWORK_LOG_LEVEL}"/>
<root level="${LOG_LEVEL}">
<appender-ref ref="FILE_OUT"/>
<appender-ref ref="STD_ERR"/>
<appender-ref ref="STD_OUT"/>

View File

@ -4,31 +4,50 @@ import com.github.stefanbirkner.systemlambda.SystemLambda
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import mu.KotlinLogging
import net.lamgc.scalabot.config.MavenRepositoryConfig
import net.lamgc.scalabot.config.ProxyConfig
import net.lamgc.scalabot.config.ProxyType
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import java.io.File
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import java.io.IOException
import java.net.Proxy
import java.net.URL
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.deleteExisting
import kotlin.test.*
internal class AppPathsTest {
@Test
fun `Consistency check`() {
for (path in AppPaths.entries) {
assertEquals(
File(path.path).canonicalPath,
path.file.canonicalPath,
"路径 File 与 Path 不一致: ${path.name}"
)
}
}
@Test
fun `Data root path priority`() {
System.setProperty("bot.path.data", "fromSystemProperties")
System.setProperty(AppPaths.PathConst.PROP_DATA_PATH, "fromSystemProperties")
assertEquals("fromSystemProperties", AppPaths.DATA_ROOT.file.path, "`DATA_ROOT`没有优先返回 Property 的值.")
System.getProperties().remove("bot.path.data")
System.getProperties().remove(AppPaths.PathConst.PROP_DATA_PATH)
val expectEnvValue = "fromEnvironmentVariable"
SystemLambda.withEnvironmentVariable("BOT_DATA_PATH", expectEnvValue).execute {
SystemLambda.withEnvironmentVariable(AppPaths.PathConst.ENV_DATA_PATH, expectEnvValue).execute {
assertEquals(
expectEnvValue, AppPaths.DATA_ROOT.file.path,
"`DATA_ROOT`没有优先返回 env 的值."
)
}
SystemLambda.withEnvironmentVariable("BOT_DATA_PATH", null).execute {
SystemLambda.withEnvironmentVariable(AppPaths.PathConst.ENV_DATA_PATH, null).execute {
assertEquals(
System.getProperty("user.dir"), AppPaths.DATA_ROOT.file.path,
"`DATA_ROOT`没有返回 System.properties `user.dir` 的值."
@ -116,5 +135,282 @@ internal class AppPathsTest {
defaultInitializerMethod.isAccessible = false
}
}
@Test
fun `loadBotConfig test`(@TempDir testDir: File) {
assertNull(loadBotConfigJson(File("/NOT_EXISTS_FILE")), "加载 BotConfigs 失败时应该返回 null.")
SystemLambda.withEnvironmentVariable(AppPaths.PathConst.ENV_DATA_PATH, testDir.canonicalPath).execute {
assertNull(loadBotConfigJson(), "加载 BotConfigs 失败时应该返回 null.")
File(testDir, "bot.json").apply {
//language=JSON5
writeText(
"""
[
{
"enabled": false,
"account": {
"name": "TestBot",
"token": "123456789:AAHErDroUTznQsOd_oZPJ6cQEj4Z5mGHO10",
"creatorId": 123456789
},
"proxy": {
"host": "localhost",
"port": 8080,
"type": "HTTP"
},
"disableBuiltInAbility": false,
"autoUpdateCommandList": true,
"extensions": [
"org.example.test:test-extension:1.0.0"
],
"baseApiUrl": "http://localhost:8080"
}
]
""".trimIndent()
)
}
val botConfigJsons = loadBotConfigJson()
assertNotNull(botConfigJsons)
assertEquals(1, botConfigJsons.size())
}
}
@Test
fun `loadAppConfig test`(@TempDir testDir: File) {
assertThrows<IOException>("加载失败时应该抛出 IOException.") {
loadAppConfig(File("/NOT_EXISTS_FILE"))
}
SystemLambda.withEnvironmentVariable(AppPaths.PathConst.ENV_DATA_PATH, testDir.canonicalPath).execute {
assertThrows<IOException>("加载失败时应该抛出 IOException.") {
loadAppConfig()
}
File(testDir, "config.json").apply {
//language=JSON5
writeText(
"""
{
"proxy": {
"type": "HTTP",
"host": "localhost",
"port": 8080
},
"metrics": {
"enable": true,
"port": 8800,
"bindAddress": "127.0.0.1",
"authenticator": {
"username": "username",
"password": "password"
}
},
"mavenRepositories": [
{
"url": "https://repository.maven.apache.org/maven2/"
}
],
"mavenLocalRepository": "file:///tmp/maven-local-repository"
}
""".trimIndent()
)
}
val appConfigs = loadAppConfig()
assertNotNull(appConfigs)
}
}
@Test
fun `ProxyType_toTelegramBotsType test`() {
val expectTypeMapping = mapOf(
ProxyType.NO_PROXY to null,
ProxyType.SOCKS5 to Proxy.Type.SOCKS,
ProxyType.SOCKS4 to Proxy.Type.SOCKS,
ProxyType.HTTP to Proxy.Type.HTTP,
ProxyType.HTTPS to Proxy.Type.HTTP
)
for (proxyType in ProxyType.entries) {
assertEquals(
expectTypeMapping[proxyType],
proxyType.toJavaProxyType(),
"ProxyType 转换失败."
)
}
}
@Test
fun `ProxyConfig_toAetherProxy test`() {
val host = "proxy.example.org"
val port = 1080
val expectNotNullProxyType = setOf(
ProxyType.HTTP,
ProxyType.HTTPS
)
for (proxyType in ProxyType.entries) {
val proxyConfig = ProxyConfig(proxyType, host, port)
val aetherProxy = proxyConfig.toAetherProxy()
if (expectNotNullProxyType.contains(proxyType)) {
assertNotNull(aetherProxy, "支持的代理类型应该不为 null.")
assertEquals(host, aetherProxy.host)
assertEquals(port, aetherProxy.port)
} else {
assertNull(aetherProxy, "不支持的代理类型应该返回 null.")
}
}
}
@Test
fun `MavenRepositoryConfig_toRemoteRepository test`() {
val defaultMavenRepositoryConfig = MavenRepositoryConfig(
url = URL(MavenRepositoryExtensionFinder.MAVEN_CENTRAL_URL),
enableReleases = true,
enableSnapshots = false
)
val remoteRepositoryWithoutId = defaultMavenRepositoryConfig.toRemoteRepository(
ProxyConfig(ProxyType.NO_PROXY, "", 0)
)
assertEquals(MavenRepositoryExtensionFinder.MAVEN_CENTRAL_URL, remoteRepositoryWithoutId.url.toString())
assertNotNull(remoteRepositoryWithoutId.id)
assertTrue(remoteRepositoryWithoutId.getPolicy(false).isEnabled)
assertFalse(remoteRepositoryWithoutId.getPolicy(true).isEnabled)
val remoteRepositoryWithId = defaultMavenRepositoryConfig.copy(id = "test-repo").toRemoteRepository(
ProxyConfig(ProxyType.HTTP, "127.0.0.1", 1080)
)
assertEquals("test-repo", remoteRepositoryWithId.id)
assertEquals(MavenRepositoryExtensionFinder.MAVEN_CENTRAL_URL, remoteRepositoryWithId.url.toString())
assertEquals("http", remoteRepositoryWithId.proxy.type)
assertEquals("127.0.0.1", remoteRepositoryWithId.proxy.host)
assertEquals(1080, remoteRepositoryWithId.proxy.port)
assertEquals(remoteRepositoryWithId.id, remoteRepositoryWithId.id)
val remoteRepositoryWithProxy = defaultMavenRepositoryConfig.copy(
id = "test-repo",
proxy = ProxyConfig(ProxyType.HTTP, "example.org", 1080).toAetherProxy()
).toRemoteRepository(ProxyConfig(ProxyType.HTTP, "localhost", 8080))
assertEquals("http", remoteRepositoryWithProxy.proxy.type)
assertEquals("example.org", remoteRepositoryWithProxy.proxy.host, "未优先使用 MavenRepositoryConfig 中的 proxy 属性.")
assertEquals(1080, remoteRepositoryWithProxy.proxy.port, "未优先使用 MavenRepositoryConfig 中的 proxy 属性.")
}
@Test
fun `checkRepositoryLayout test`() {
val noProxyConfig = ProxyConfig(ProxyType.NO_PROXY, "", 0)
assertEquals(
"default", MavenRepositoryConfig(url = URL("https://repo.example.org"))
.toRemoteRepository(noProxyConfig).contentType
)
assertEquals(
"legacy", MavenRepositoryConfig(url = URL("https://repo.example.org"), layout = "LEgaCY")
.toRemoteRepository(noProxyConfig).contentType
)
assertThrows<IllegalArgumentException> {
MavenRepositoryConfig(
url = URL("https://repo.example.org"),
layout = "NOT_EXISTS_LAYOUT"
).toRemoteRepository(noProxyConfig)
}
}
@Test
fun `initialFiles test`(@TempDir testDir: Path) {
// 这么做是为了让日志文件创建在其他地方, 由于日志文件在运行时会持续占用, 在 windows 中文件会被锁定,
// 导致测试框架无法正常清除测试所使用的临时文件夹.
val logsDir = Files.createTempDirectory("ammmmmm-logs-")
System.setProperty(AppPaths.PathConst.PROP_DATA_PATH, logsDir.toString())
assertEquals(logsDir.toString(), AppPaths.DATA_ROOT.path, "日志目录设定失败.")
KotlinLogging.logger("TEST").error { "日志占用.(无需理会), 日志目录: $logsDir" }
AppPaths.DATA_LOGS.file.listFiles { _, name -> name.endsWith(".log") }?.forEach {
it.deleteOnExit()
}
val fullInitializeDir = Files.createTempDirectory(testDir, "fullInitialize")
fullInitializeDir.deleteExisting()
System.setProperty(AppPaths.PathConst.PROP_DATA_PATH, fullInitializeDir.toString())
assertEquals(fullInitializeDir.toString(), AppPaths.DATA_ROOT.path, "测试路径设定失败.")
assertTrue(initialFiles(), "方法未能提醒用户编辑初始配置文件.")
for (path in AppPaths.entries) {
assertTrue(path.file.exists(), "文件未初始化成功: ${path.path}")
if (path.file.isFile) {
assertNotEquals(0, path.file.length(), "文件未初始化成功(大小为 0): ${path.path}")
}
path.reset()
}
assertFalse(initialFiles(), "方法试图在配置已初始化的情况下提醒用户编辑初始配置文件.")
for (path in AppPaths.entries) {
assertTrue(path.file.exists(), "文件未初始化成功: ${path.path}")
if (path.file.isFile) {
assertNotEquals(0, path.file.length(), "文件未初始化成功(大小为 0): ${path.path}")
}
path.reset()
}
assertTrue(AppPaths.CONFIG_APPLICATION.file.delete(), "config.json 删除失败.")
assertFalse(initialFiles(), "方法试图在部分配置已初始化的情况下提醒用户编辑初始配置文件.")
for (path in AppPaths.entries) {
assertTrue(path.file.exists(), "文件未初始化成功: ${path.path}")
if (path.file.isFile) {
assertNotEquals(0, path.file.length(), "文件未初始化成功(大小为 0): ${path.path}")
}
path.reset()
}
assertTrue(AppPaths.CONFIG_BOT.file.delete(), "bot.json 删除失败.")
assertFalse(initialFiles(), "方法试图在部分配置已初始化的情况下提醒用户编辑初始配置文件.")
for (path in AppPaths.entries) {
assertTrue(path.file.exists(), "文件未初始化成功: ${path.path}")
if (path.file.isFile) {
assertNotEquals(0, path.file.length(), "文件未初始化成功(大小为 0): ${path.path}")
}
path.reset()
}
assertTrue(AppPaths.CONFIG_APPLICATION.file.delete(), "config.json 删除失败.")
assertTrue(AppPaths.CONFIG_BOT.file.delete(), "bot.json 删除失败.")
assertTrue(
initialFiles(),
"在主要配置文件(config.json 和 bot.json)不存在的情况下初始化文件后, 方法未能提醒用户编辑初始配置文件."
)
for (path in AppPaths.entries) {
assertTrue(path.file.exists(), "文件未初始化成功: ${path.path}")
if (path.file.isFile) {
assertNotEquals(0, path.file.length(), "文件未初始化成功(大小为 0): ${path.path}")
}
}
AppPaths.CONFIG_APPLICATION.file.writeText("Test-APPLICATION")
AppPaths.CONFIG_BOT.file.writeText("Test-BOT")
assertFalse(initialFiles(), "方法试图在部分配置已初始化的情况下提醒用户编辑初始配置文件.")
assertEquals(
"Test-APPLICATION", AppPaths.CONFIG_APPLICATION.file.readText(),
"config.json 被覆盖. initialized 并未阻止重复初始化."
)
assertEquals(
"Test-BOT", AppPaths.CONFIG_BOT.file.readText(),
"bot.json 被覆盖. initialized 并未阻止重复初始化."
)
System.getProperties().remove(AppPaths.PathConst.PROP_DATA_PATH)
}
private fun AppPaths.reset() {
val method = AppPaths::class.java.getDeclaredMethod("reset")
method.isAccessible = true
method.invoke(this)
method.isAccessible = false
}
}

View File

@ -0,0 +1,27 @@
package util
import net.lamgc.scalabot.util.TelegramBotAccounts
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
class TelegramBotAccountsTest {
@Test
fun getBotAccountIdTest() {
val expectToken = "1234567890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"
val actual: Long = TelegramBotAccounts.getBotAccountId(expectToken)
assertEquals(1234567890, actual)
val badTokenA = "12c34d56a7890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"
assertThrows(
IllegalArgumentException::class.java
) { TelegramBotAccounts.getBotAccountId(badTokenA) }
val badTokenB = "12c34d56a7890AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo"
assertThrows(
IllegalArgumentException::class.java
) { TelegramBotAccounts.getBotAccountId(badTokenB) }
}
}

View File

@ -5,7 +5,7 @@ plugins {
dependencies {
compileOnly(project(":scalabot-extension"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}

View File

@ -1,8 +1,8 @@
package net.lamgc.scalabot.simple;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.abilitybots.api.objects.*;
import org.telegram.abilitybots.api.util.AbilityExtension;
import org.telegram.telegrambots.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.abilitybots.api.objects.*;
import org.telegram.telegrambots.abilitybots.api.util.AbilityExtension;
public class SayHelloExtension implements AbilityExtension {
@ -27,7 +27,7 @@ public class SayHelloExtension implements AbilityExtension {
String msg = "Hello! " + ctx.user().getUserName() +
" ( " + ctx.user().getId() + " ) [ " + ctx.user().getLanguageCode() + " ]" + "\n" +
"Current Chat ID: " + ctx.chatId();
ctx.bot().silent().send(msg, ctx.chatId());
ctx.bot().getSilent().send(msg, ctx.chatId());
})
.build();
}
@ -36,13 +36,13 @@ public class SayHelloExtension implements AbilityExtension {
* 更具特色的 `Say hello`.
*/
public Ability test() {
ReplyFlow botHello = ReplyFlow.builder(bot.db())
ReplyFlow botHello = ReplyFlow.builder(bot.getDb())
.enableStats("say_hello")
.action((bot, upd) -> bot.silent().send("What is u name?", upd.getMessage().getChatId()))
.action((bot, upd) -> bot.getSilent().send("What is u name?", upd.getMessage().getChatId()))
.onlyIf(update -> update.hasMessage()
&& update.getMessage().hasText()
&& "hello".equalsIgnoreCase(update.getMessage().getText()))
.next(Reply.of((bot, upd) -> bot.silent()
.next(Reply.of((bot, upd) -> bot.getSilent()
.send("OK! You name is " + upd.getMessage().getText().substring("my name is ".length()), upd.getMessage().getChatId()),
upd -> upd.hasMessage()
&& upd.getMessage().hasText()
@ -55,7 +55,7 @@ public class SayHelloExtension implements AbilityExtension {
.locality(Locality.ALL)
.privacy(Privacy.PUBLIC)
.enableStats()
.action(ctx -> ctx.bot().silent().send("Hello!", ctx.chatId()))
.action(ctx -> ctx.bot().getSilent().send("Hello!", ctx.chatId()))
.reply(botHello)
.build();
}

View File

@ -1,15 +1,16 @@
package net.lamgc.scalabot.simple;
import net.lamgc.scalabot.extension.BotExtensionCreateOptions;
import net.lamgc.scalabot.extension.BotExtensionFactory;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.abilitybots.api.util.AbilityExtension;
import org.telegram.telegrambots.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.abilitybots.api.util.AbilityExtension;
import java.io.File;
public class SimpleExtensionFactory implements BotExtensionFactory {
@Override
public AbilityExtension createExtensionInstance(BaseAbilityBot bot, File shareDataFolder) {
public AbilityExtension createExtensionInstance(BaseAbilityBot bot, File shareDataFolder, BotExtensionCreateOptions options) {
return new SayHelloExtension(bot);
}

View File

@ -1,16 +1,18 @@
plugins {
kotlin("jvm")
java
`java-library`
jacoco
`maven-publish`
signing
}
dependencies {
api("org.telegram:telegrambots-abilities:6.0.1")
api("org.slf4j:slf4j-api:1.7.36")
implementation("commons-codec:commons-codec:1.16.1")
api("org.telegram:telegrambots-abilities:8.0.0")
api(project(":scalabot-meta"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testImplementation("org.mockito:mockito-core:4.6.1")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testImplementation("org.mockito:mockito-core:5.11.0")
testImplementation("org.telegram:telegrambots-client:8.0.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
@ -23,29 +25,30 @@ tasks.withType<Javadoc> {
java {
withJavadocJar()
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.test {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}
tasks.jacocoTestReport {
dependsOn(tasks.test)
}
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
publishing {
repositories {
if (project.version.toString().endsWith("-SNAPSHOT")) {
maven("https://nexus.kuku.me/repository/maven-snapshots/") {
maven("https://git.lamgc.me/api/packages/LamGC/maven") {
credentials {
username = project.properties["repo.credentials.private.username"].toString()
password = project.properties["repo.credentials.private.password"].toString()
}
}
} else {
maven("https://nexus.kuku.me/repository/maven-releases/") {
credentials {
username = project.properties["repo.credentials.private.username"].toString()
password = project.properties["repo.credentials.private.password"].toString()
}
username = project.properties["repo.credentials.self-git.username"].toString()
password = project.properties["repo.credentials.self-git.password"].toString()
}
}
}

View File

@ -0,0 +1,44 @@
package net.lamgc.scalabot.extension;
import net.lamgc.scalabot.config.ProxyConfig;
/**
* BotExtension 创建参数.
* <p>
* 通过该类可向 {@link BotExtensionFactory} 提供更多创建 BotExtension 时可用的参数.
*/
@SuppressWarnings("unused")
public class BotExtensionCreateOptions {
private final long botAccountId;
private final ProxyConfig proxy;
/**
* 构造新的 BotExtensionCreateOptions.
*
* @param botAccountId 创建扩展的 Bot 账户 Id.
* @param proxy Bot 所使用的代理配置.
*/
public BotExtensionCreateOptions(long botAccountId, ProxyConfig proxy) {
this.botAccountId = botAccountId;
this.proxy = proxy;
}
/**
* 获取 Bot 使用的代理信息.
*
* @return 返回 Bot TelegramClient 所使用的代理配置.
*/
public ProxyConfig getProxy() {
return proxy;
}
/**
* 获取 Bot 的账户 Id.
*
* @return 返回 Bot 的账户 Id.
*/
public long getBotAccountId() {
return botAccountId;
}
}

View File

@ -1,7 +1,8 @@
package net.lamgc.scalabot.extension;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.abilitybots.api.util.AbilityExtension;
import org.telegram.telegrambots.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.abilitybots.api.db.DBContext;
import org.telegram.telegrambots.abilitybots.api.util.AbilityExtension;
import java.io.File;
@ -9,7 +10,7 @@ import java.io.File;
* 该接口用于为指定的 {@link BaseAbilityBot} 创建扩展.
*
* <p> 由于 AbilityExtension 无法直接获取 {@link BaseAbilityBot}
* 数据库对象 {@link org.telegram.abilitybots.api.db.DBContext},
* 数据库对象 {@link DBContext},
* 所以将通过该接口工厂来创建扩展对象.
*
* @author LamGC
@ -20,7 +21,7 @@ public interface BotExtensionFactory {
/**
* 为给定的 {@link BaseAbilityBot} 对象创建扩展.
*
* <p> 如扩展无使用 {@link org.telegram.abilitybots.api.db.DBContext} 的话,
* <p> 如扩展无使用 {@link DBContext} 的话,
* 也可以返回扩展单例, 因为 AbilityBot 本身并不禁止多个机器人共用一个扩展对象
* (AbilityBot 只是调用了扩展中的方法来创建 Ability 对象).
*
@ -30,8 +31,10 @@ public interface BotExtensionFactory {
* <pre> $DATA_ROOT/data/extensions/{GroupId}/{ArtifactId}</pre>
* <b>同一个扩展包的 Factory</b> 接收到的共享数据目录<b>都是一样的</b>,
* 建议将数据存储在数据目录中, 便于数据的存储管理.
* @param options 创建扩展时可用的参数.
* @return 返回为该 Bot 对象创建的扩展对象, 如果不希望为该机器人提供扩展, 可返回 {@code null}.
* @since 0.7.0
*/
AbilityExtension createExtensionInstance(BaseAbilityBot bot, File shareDataFolder);
AbilityExtension createExtensionInstance(BaseAbilityBot bot, File shareDataFolder, BotExtensionCreateOptions options);
}

View File

@ -1,38 +1,17 @@
package net.lamgc.scalabot.extension.util;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.abilitybots.api.bot.BaseAbilityBot;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AbilityBots {
private final static Pattern botTokenPattern = Pattern.compile("([1-9]\\d+):([A-Za-z\\d_-]{35,})");
/**
* 一些开发扩展中可以用到的工具类.
*/
public final class AbilityBots {
private AbilityBots() {
}
/**
* 获取 AbilityBot 的账户 Id.
*
* <p> 账户 Id 来自于 botToken , token 的格式为 "[AccountId]:[Secret]".
* <p> 账户 Id 的真实性与 botToken 的有效性有关, 本方法并不会确保 botToken 的有效性, 一般情况下也无需考虑 Id 的有效性,
* 如果有需要, 可尝试通过调用 {@link org.telegram.telegrambots.meta.api.methods.GetMe} 来确保 botToken 的有效性.
*
* @param bot 要获取账户 Id AbilityBot 对象.
* @return 返回 AbilityBot 的账户 Id.
* @throws IllegalArgumentException AbilityBot botToken 格式错误时抛出该异常.
*/
public static long getBotAccountId(BaseAbilityBot bot) {
String botToken = bot.getBotToken();
Matcher matcher = botTokenPattern.matcher(botToken);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid token format.");
}
return Long.parseLong(matcher.group(1));
}
/**
* 取消某一对话的状态机.
*
@ -41,7 +20,7 @@ public class AbilityBots {
* @return 如果状态机存在, 则删除后返回 true, 不存在(未开启任何状态机, 即没有触发任何 Reply)则返回 false.
*/
public static boolean cancelReplyState(BaseAbilityBot bot, long chatId) {
Map<Long, Integer> stateMap = bot.db().getMap("user_state_replies");
Map<Long, Integer> stateMap = bot.getDb().getMap("user_state_replies");
if (!stateMap.containsKey(chatId)) {
return false;
}

View File

@ -2,22 +2,35 @@ package net.lamgc.scalabot.extension.util;
import org.junit.jupiter.api.Test;
import org.mapdb.DBMaker;
import org.telegram.abilitybots.api.bot.AbilityBot;
import org.telegram.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.abilitybots.api.db.MapDBContext;
import org.telegram.abilitybots.api.objects.*;
import org.telegram.abilitybots.api.sender.SilentSender;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.abilitybots.api.bot.AbilityBot;
import org.telegram.telegrambots.abilitybots.api.bot.BaseAbilityBot;
import org.telegram.telegrambots.abilitybots.api.db.MapDBContext;
import org.telegram.telegrambots.abilitybots.api.objects.*;
import org.telegram.telegrambots.abilitybots.api.sender.SilentSender;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.message.Message;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
public class AbilityBotsTest {
public static final User USER = new User(1L, "first", false, "last", "username", null, false, false, false);
public static final User CREATOR = new User(1337L, "creatorFirst", false, "creatorLast", "creatorUsername", null, false, false, false);
public static final User USER = User.builder()
.userName("username")
.id(1L)
.firstName("first")
.lastName("last")
.isBot(false)
.build();
public static final User CREATOR = User.builder()
.userName("creatorUsername")
.id(1337L)
.firstName("creatorFirst")
.lastName("creatorLast")
.isBot(false)
.build();
static Update mockFullUpdate(BaseAbilityBot bot, User user, String args) {
bot.users().put(USER.getId(), USER);
@ -39,73 +52,67 @@ public class AbilityBotsTest {
return update;
}
@Test
void getBotAccountIdTest() {
String expectToken = "1234567890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo";
long actual = AbilityBots.getBotAccountId(new TestingAbilityBot(expectToken, "test"));
assertEquals(1234567890, actual);
String badTokenA = "12c34d56a7890:AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo";
assertThrows(IllegalArgumentException.class, () ->
AbilityBots.getBotAccountId(new TestingAbilityBot(badTokenA, "test")));
String badTokenB = "12c34d56a7890AAHXcNDBRZTKfyPED5Gi3PZDIKPOM6xhxwo";
assertThrows(IllegalArgumentException.class, () ->
AbilityBots.getBotAccountId(new TestingAbilityBot(badTokenB, "test")));
}
@Test
void cancelReplyStateTest() {
User userA = new User(10001L, "first", false, "last", "username", null, false, false, false);
User userB = new User(10101L, "first", false, "last", "username", null, false, false, false);
User userA = User.builder()
.id(10001L)
.firstName("first")
.lastName("last")
.userName("username")
.isBot(false)
.build();
User userB = User.builder()
.id(10101L)
.firstName("first")
.lastName("last")
.userName("username")
.isBot(false)
.build();
SilentSender silent = mock(SilentSender.class);
BaseAbilityBot bot = new TestingAbilityBot("", "", silent);
BaseAbilityBot bot = new TestingAbilityBot("", silent);
bot.onRegister();
bot.onUpdateReceived(mockFullUpdate(bot, userA, "/set_reply"));
bot.consume(mockFullUpdate(bot, userA, "/set_reply"));
verify(silent, times(1)).send("Reply set!", userA.getId());
bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_01"));
bot.consume(mockFullUpdate(bot, userA, "reply_01"));
verify(silent, times(1)).send("Reply 01", userA.getId());
assertTrue(AbilityBots.cancelReplyState(bot, userA.getId()));
bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_02"));
bot.consume(mockFullUpdate(bot, userA, "reply_02"));
verify(silent, never()).send("Reply 02", userA.getId());
assertFalse(AbilityBots.cancelReplyState(bot, userB.getId()));
silent = mock(SilentSender.class);
bot = new TestingAbilityBot("", "", silent);
bot = new TestingAbilityBot("", silent);
bot.onRegister();
bot.onUpdateReceived(mockFullUpdate(bot, userA, "/set_reply"));
bot.consume(mockFullUpdate(bot, userA, "/set_reply"));
verify(silent, times(1)).send("Reply set!", userA.getId());
bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_01"));
bot.consume(mockFullUpdate(bot, userA, "reply_01"));
verify(silent, times(1)).send("Reply 01", userA.getId());
bot.onUpdateReceived(mockFullUpdate(bot, userA, "reply_02"));
bot.consume(mockFullUpdate(bot, userA, "reply_02"));
verify(silent, times(1)).send("Reply 02", userA.getId());
}
public static class TestingAbilityBot extends AbilityBot {
public TestingAbilityBot(String botToken, String botUsername) {
super(botToken, botUsername, new MapDBContext(DBMaker.heapDB().make()));
}
public TestingAbilityBot(String botToken, String botUsername, SilentSender silentSender) {
super(botToken, botUsername, new MapDBContext(DBMaker.heapDB().make()));
public TestingAbilityBot(String botUsername, SilentSender silentSender) {
super(new NoOpTelegramClient(), botUsername, new MapDBContext(DBMaker.heapDB().make()));
this.silent = silentSender;
}
@SuppressWarnings("unused")
public Ability setReply() {
return Ability.builder()
.name("set_reply")
.enableStats()
.locality(Locality.ALL)
.privacy(Privacy.PUBLIC)
.action(ctx -> ctx.bot().silent().send("Reply set!", ctx.chatId()))
.reply(ReplyFlow.builder(db())
.action((bot, upd) -> bot.silent().send("Reply 01", upd.getMessage().getChatId()))
.action(ctx -> ctx.bot().getSilent().send("Reply set!", ctx.chatId()))
.reply(ReplyFlow.builder(getDb())
.action((bot, upd) -> bot.getSilent().send("Reply 01", upd.getMessage().getChatId()))
.onlyIf(upd -> upd.hasMessage() && upd.getMessage().getText().equals("reply_01"))
.next(Reply.of((bot, upd) ->
bot.silent().send("Reply 02", upd.getMessage().getChatId()),
bot.getSilent().send("Reply 02", upd.getMessage().getChatId()),
upd -> upd.hasMessage() && upd.getMessage().getText().equals("reply_02")))
.build()
)

View File

@ -0,0 +1,229 @@
package net.lamgc.scalabot.extension.util;
import org.telegram.telegrambots.meta.api.methods.botapimethods.BotApiMethod;
import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto;
import org.telegram.telegrambots.meta.api.methods.send.*;
import org.telegram.telegrambots.meta.api.methods.stickers.*;
import org.telegram.telegrambots.meta.api.methods.updates.SetWebhook;
import org.telegram.telegrambots.meta.api.methods.updatingmessages.EditMessageMedia;
import org.telegram.telegrambots.meta.api.objects.File;
import org.telegram.telegrambots.meta.api.objects.message.Message;
import org.telegram.telegrambots.meta.generics.TelegramClient;
import java.io.InputStream;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.CompletableFuture;
class NoOpTelegramClient implements TelegramClient {
@Override
public <T extends Serializable, Method extends BotApiMethod<T>> CompletableFuture<T> executeAsync(Method method) {
return null;
}
@Override
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) {
return null;
}
@Override
public Message execute(SendDocument sendDocument) {
return null;
}
@Override
public Message execute(SendPhoto sendPhoto) {
return null;
}
@Override
public Boolean execute(SetWebhook setWebhook) {
return null;
}
@Override
public Message execute(SendVideo sendVideo) {
return null;
}
@Override
public Message execute(SendVideoNote sendVideoNote) {
return null;
}
@Override
public Message execute(SendSticker sendSticker) {
return null;
}
@Override
public Message execute(SendAudio sendAudio) {
return null;
}
@Override
public Message execute(SendVoice sendVoice) {
return null;
}
@Override
public List<Message> execute(SendMediaGroup sendMediaGroup) {
return List.of();
}
@Override
public List<Message> execute(SendPaidMedia sendPaidMedia) {
return List.of();
}
@Override
public Boolean execute(SetChatPhoto setChatPhoto) {
return null;
}
@Override
public Boolean execute(AddStickerToSet addStickerToSet) {
return null;
}
@Override
public Boolean execute(ReplaceStickerInSet replaceStickerInSet) {
return null;
}
@Override
public Boolean execute(SetStickerSetThumbnail setStickerSetThumbnail) {
return null;
}
@Override
public Boolean execute(CreateNewStickerSet createNewStickerSet) {
return null;
}
@Override
public File execute(UploadStickerFile uploadStickerFile) {
return null;
}
@Override
public Serializable execute(EditMessageMedia editMessageMedia) {
return null;
}
@Override
public java.io.File downloadFile(File file) {
return null;
}
@Override
public InputStream downloadFileAsStream(File file) {
return null;
}
@Override
public Message execute(SendAnimation sendAnimation) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendDocument sendDocument) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendPhoto sendPhoto) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(SetWebhook setWebhook) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendVideo sendVideo) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendVideoNote sendVideoNote) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendSticker sendSticker) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendAudio sendAudio) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendVoice sendVoice) {
return null;
}
@Override
public CompletableFuture<List<Message>> executeAsync(SendMediaGroup sendMediaGroup) {
return null;
}
@Override
public CompletableFuture<List<Message>> executeAsync(SendPaidMedia sendPaidMedia) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(SetChatPhoto setChatPhoto) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(AddStickerToSet addStickerToSet) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(ReplaceStickerInSet replaceStickerInSet) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(SetStickerSetThumbnail setStickerSetThumbnail) {
return null;
}
@Override
public CompletableFuture<Boolean> executeAsync(CreateNewStickerSet createNewStickerSet) {
return null;
}
@Override
public CompletableFuture<File> executeAsync(UploadStickerFile uploadStickerFile) {
return null;
}
@Override
public CompletableFuture<Serializable> executeAsync(EditMessageMedia editMessageMedia) {
return null;
}
@Override
public CompletableFuture<Message> executeAsync(SendAnimation sendAnimation) {
return null;
}
@Override
public CompletableFuture<java.io.File> downloadFileAsync(File file) {
return null;
}
@Override
public CompletableFuture<InputStream> downloadFileAsStreamAsync(File file) {
return null;
}
}

13
scalabot-meta/README.md Normal file
View File

@ -0,0 +1,13 @@
# scalabot-meta
本模块用于将 ScalaBot 的一些配置相关内容发布出去,以便于其他项目使用。
主要是配置类和相应的 Gson 序列化器(如果有,或者必要)。
## 关于序列化器
强烈建议使用序列化器!由于 Kotlin 与 Gson 之间的一些兼容性问题
(参见[本提交](https://github.com/LamGC/ScalaBot/commit/084280564af58d1af22db5b57c67577d93bd820e)
如果直接让 Gson 解析 Kotlin Data 类,将会出现一些潜在的问题(比如无法使用默认值)。
部分序列化器也可以帮助检查字段值是否合法,以防止因字段值不正确导致出现更多的问题
(例如 BotAccount 中,如果 `token` 的格式有误,那么获取 `id` 时将引发 `NumberFormatException` 异常)。

View File

@ -0,0 +1,201 @@
public final class net/lamgc/scalabot/config/AppConfig {
public fun <init> ()V
public fun <init> (Lnet/lamgc/scalabot/config/ProxyConfig;Lnet/lamgc/scalabot/config/MetricsConfig;Ljava/util/List;Ljava/lang/String;)V
public synthetic fun <init> (Lnet/lamgc/scalabot/config/ProxyConfig;Lnet/lamgc/scalabot/config/MetricsConfig;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lnet/lamgc/scalabot/config/ProxyConfig;
public final fun component2 ()Lnet/lamgc/scalabot/config/MetricsConfig;
public final fun component3 ()Ljava/util/List;
public final fun component4 ()Ljava/lang/String;
public final fun copy (Lnet/lamgc/scalabot/config/ProxyConfig;Lnet/lamgc/scalabot/config/MetricsConfig;Ljava/util/List;Ljava/lang/String;)Lnet/lamgc/scalabot/config/AppConfig;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/AppConfig;Lnet/lamgc/scalabot/config/ProxyConfig;Lnet/lamgc/scalabot/config/MetricsConfig;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lnet/lamgc/scalabot/config/AppConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getMavenLocalRepository ()Ljava/lang/String;
public final fun getMavenRepositories ()Ljava/util/List;
public final fun getMetrics ()Lnet/lamgc/scalabot/config/MetricsConfig;
public final fun getProxy ()Lnet/lamgc/scalabot/config/ProxyConfig;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/BotAccount {
public fun <init> (Ljava/lang/String;Ljava/lang/String;J)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()J
public final fun copy (Ljava/lang/String;Ljava/lang/String;J)Lnet/lamgc/scalabot/config/BotAccount;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/BotAccount;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lnet/lamgc/scalabot/config/BotAccount;
public fun equals (Ljava/lang/Object;)Z
public final fun getCreatorId ()J
public final fun getId ()J
public final fun getName ()Ljava/lang/String;
public final fun getToken ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/BotConfig {
public fun <init> (ZLnet/lamgc/scalabot/config/BotAccount;ZZLjava/util/Set;Lnet/lamgc/scalabot/config/ProxyConfig;Ljava/lang/String;)V
public synthetic fun <init> (ZLnet/lamgc/scalabot/config/BotAccount;ZZLjava/util/Set;Lnet/lamgc/scalabot/config/ProxyConfig;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component2 ()Lnet/lamgc/scalabot/config/BotAccount;
public final fun component3 ()Z
public final fun component4 ()Z
public final fun component5 ()Ljava/util/Set;
public final fun component6 ()Lnet/lamgc/scalabot/config/ProxyConfig;
public final fun component7 ()Ljava/lang/String;
public final fun copy (ZLnet/lamgc/scalabot/config/BotAccount;ZZLjava/util/Set;Lnet/lamgc/scalabot/config/ProxyConfig;Ljava/lang/String;)Lnet/lamgc/scalabot/config/BotConfig;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/BotConfig;ZLnet/lamgc/scalabot/config/BotAccount;ZZLjava/util/Set;Lnet/lamgc/scalabot/config/ProxyConfig;Ljava/lang/String;ILjava/lang/Object;)Lnet/lamgc/scalabot/config/BotConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAccount ()Lnet/lamgc/scalabot/config/BotAccount;
public final fun getAutoUpdateCommandList ()Z
public final fun getBaseApiTelegramUrl ()Lorg/telegram/telegrambots/meta/TelegramUrl;
public final fun getBaseApiUrl ()Ljava/lang/String;
public final fun getDisableBuiltInAbility ()Z
public final fun getEnabled ()Z
public final fun getExtensions ()Ljava/util/Set;
public final fun getProxy ()Lnet/lamgc/scalabot/config/ProxyConfig;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/ConfigsKt {
public static final fun getDefaultTelegramApiUrl ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/MavenRepositoryConfig {
public fun <init> (Ljava/lang/String;Ljava/net/URL;Lorg/eclipse/aether/repository/Proxy;Ljava/lang/String;ZZLorg/eclipse/aether/repository/Authentication;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/net/URL;Lorg/eclipse/aether/repository/Proxy;Ljava/lang/String;ZZLorg/eclipse/aether/repository/Authentication;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/net/URL;
public final fun component3 ()Lorg/eclipse/aether/repository/Proxy;
public final fun component4 ()Ljava/lang/String;
public final fun component5 ()Z
public final fun component6 ()Z
public final fun component7 ()Lorg/eclipse/aether/repository/Authentication;
public final fun copy (Ljava/lang/String;Ljava/net/URL;Lorg/eclipse/aether/repository/Proxy;Ljava/lang/String;ZZLorg/eclipse/aether/repository/Authentication;)Lnet/lamgc/scalabot/config/MavenRepositoryConfig;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/MavenRepositoryConfig;Ljava/lang/String;Ljava/net/URL;Lorg/eclipse/aether/repository/Proxy;Ljava/lang/String;ZZLorg/eclipse/aether/repository/Authentication;ILjava/lang/Object;)Lnet/lamgc/scalabot/config/MavenRepositoryConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAuthentication ()Lorg/eclipse/aether/repository/Authentication;
public final fun getEnableReleases ()Z
public final fun getEnableSnapshots ()Z
public final fun getId ()Ljava/lang/String;
public final fun getLayout ()Ljava/lang/String;
public final fun getProxy ()Lorg/eclipse/aether/repository/Proxy;
public final fun getUrl ()Ljava/net/URL;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/MetricsConfig {
public fun <init> ()V
public fun <init> (ZILjava/lang/String;Lnet/lamgc/scalabot/config/UsernameAuthenticator;)V
public synthetic fun <init> (ZILjava/lang/String;Lnet/lamgc/scalabot/config/UsernameAuthenticator;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component2 ()I
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()Lnet/lamgc/scalabot/config/UsernameAuthenticator;
public final fun copy (ZILjava/lang/String;Lnet/lamgc/scalabot/config/UsernameAuthenticator;)Lnet/lamgc/scalabot/config/MetricsConfig;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/MetricsConfig;ZILjava/lang/String;Lnet/lamgc/scalabot/config/UsernameAuthenticator;ILjava/lang/Object;)Lnet/lamgc/scalabot/config/MetricsConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getAuthenticator ()Lnet/lamgc/scalabot/config/UsernameAuthenticator;
public final fun getBindAddress ()Ljava/lang/String;
public final fun getEnable ()Z
public final fun getPort ()I
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/ProxyConfig {
public fun <init> ()V
public fun <init> (Lnet/lamgc/scalabot/config/ProxyType;Ljava/lang/String;I)V
public synthetic fun <init> (Lnet/lamgc/scalabot/config/ProxyType;Ljava/lang/String;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lnet/lamgc/scalabot/config/ProxyType;
public final fun component2 ()Ljava/lang/String;
public final fun component3 ()I
public final fun copy (Lnet/lamgc/scalabot/config/ProxyType;Ljava/lang/String;I)Lnet/lamgc/scalabot/config/ProxyConfig;
public static synthetic fun copy$default (Lnet/lamgc/scalabot/config/ProxyConfig;Lnet/lamgc/scalabot/config/ProxyType;Ljava/lang/String;IILjava/lang/Object;)Lnet/lamgc/scalabot/config/ProxyConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getHost ()Ljava/lang/String;
public final fun getPort ()I
public final fun getType ()Lnet/lamgc/scalabot/config/ProxyType;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class net/lamgc/scalabot/config/ProxyType : java/lang/Enum {
public static final field HTTP Lnet/lamgc/scalabot/config/ProxyType;
public static final field HTTPS Lnet/lamgc/scalabot/config/ProxyType;
public static final field NO_PROXY Lnet/lamgc/scalabot/config/ProxyType;
public static final field SOCKS4 Lnet/lamgc/scalabot/config/ProxyType;
public static final field SOCKS5 Lnet/lamgc/scalabot/config/ProxyType;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public static fun valueOf (Ljava/lang/String;)Lnet/lamgc/scalabot/config/ProxyType;
public static fun values ()[Lnet/lamgc/scalabot/config/ProxyType;
}
public final class net/lamgc/scalabot/config/UsernameAuthenticator : com/sun/net/httpserver/BasicAuthenticator {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public fun checkCredentials (Ljava/lang/String;Ljava/lang/String;)Z
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public final fun toJsonObject ()Lcom/google/gson/JsonObject;
}
public final class net/lamgc/scalabot/config/serializer/ArtifactSerializer : com/google/gson/JsonDeserializer, com/google/gson/JsonSerializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/ArtifactSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lorg/eclipse/aether/artifact/Artifact;
public synthetic fun serialize (Ljava/lang/Object;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
public fun serialize (Lorg/eclipse/aether/artifact/Artifact;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
}
public final class net/lamgc/scalabot/config/serializer/AuthenticationSerializer : com/google/gson/JsonDeserializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/AuthenticationSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lorg/eclipse/aether/repository/Authentication;
}
public final class net/lamgc/scalabot/config/serializer/BotAccountSerializer : com/google/gson/JsonDeserializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/BotAccountSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/BotAccount;
}
public final class net/lamgc/scalabot/config/serializer/BotConfigSerializer : com/google/gson/JsonDeserializer, com/google/gson/JsonSerializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/BotConfigSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/BotConfig;
public synthetic fun serialize (Ljava/lang/Object;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
public fun serialize (Lnet/lamgc/scalabot/config/BotConfig;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
}
public final class net/lamgc/scalabot/config/serializer/MavenRepositoryConfigSerializer : com/google/gson/JsonDeserializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/MavenRepositoryConfigSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/MavenRepositoryConfig;
}
public final class net/lamgc/scalabot/config/serializer/ProxyConfigSerializer : com/google/gson/JsonDeserializer, com/google/gson/JsonSerializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/ProxyConfigSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/ProxyConfig;
public synthetic fun serialize (Ljava/lang/Object;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
public fun serialize (Lnet/lamgc/scalabot/config/ProxyConfig;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
}
public final class net/lamgc/scalabot/config/serializer/ProxyTypeSerializer : com/google/gson/JsonDeserializer, com/google/gson/JsonSerializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/ProxyTypeSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/ProxyType;
public synthetic fun serialize (Ljava/lang/Object;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
public fun serialize (Lnet/lamgc/scalabot/config/ProxyType;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
}
public final class net/lamgc/scalabot/config/serializer/UsernameAuthenticatorSerializer : com/google/gson/JsonDeserializer, com/google/gson/JsonSerializer {
public static final field INSTANCE Lnet/lamgc/scalabot/config/serializer/UsernameAuthenticatorSerializer;
public synthetic fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Ljava/lang/Object;
public fun deserialize (Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/lamgc/scalabot/config/UsernameAuthenticator;
public synthetic fun serialize (Ljava/lang/Object;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
public fun serialize (Lnet/lamgc/scalabot/config/UsernameAuthenticator;Ljava/lang/reflect/Type;Lcom/google/gson/JsonSerializationContext;)Lcom/google/gson/JsonElement;
}

View File

@ -1,39 +1,47 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("jvm")
id("org.jetbrains.kotlinx.kover")
id("org.jetbrains.dokka") version "1.7.0"
id("org.jetbrains.dokka") version "1.9.20"
`maven-publish`
signing
id("org.jetbrains.kotlinx.binary-compatibility-validator")
}
dependencies {
val aetherVersion = "1.1.0"
implementation("org.eclipse.aether:aether-api:$aetherVersion")
api("org.eclipse.aether:aether-api:$aetherVersion")
implementation("org.eclipse.aether:aether-util:$aetherVersion")
implementation("org.telegram:telegrambots-meta:6.0.1")
implementation("org.telegram:telegrambots-meta:8.0.0")
implementation("com.google.code.gson:gson:2.9.0")
api("com.google.code.gson:gson:2.11.0")
testImplementation(kotlin("test"))
testImplementation("io.mockk:mockk:1.12.4")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.2")
testImplementation("io.mockk:mockk:1.13.13")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.1")
dokkaHtmlPlugin("org.jetbrains.dokka:javadoc-plugin:1.7.0")
dokkaHtmlPlugin("org.jetbrains.dokka:javadoc-plugin:2.0.0")
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "11"
compilerOptions {
jvmTarget = JvmTarget.JVM_17
}
}
java {
withJavadocJar()
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
tasks.getByName<Test>("test") {
@ -46,19 +54,10 @@ val javadocJar = tasks.named<Jar>("javadocJar") {
publishing {
repositories {
if (project.version.toString().endsWith("-SNAPSHOT", ignoreCase = true)) {
maven("https://nexus.kuku.me/repository/maven-snapshots/") {
maven("https://git.lamgc.me/api/packages/LamGC/maven") {
credentials {
username = project.properties["repo.credentials.private.username"].toString()
password = project.properties["repo.credentials.private.password"].toString()
}
}
} else {
maven("https://nexus.kuku.me/repository/maven-releases/") {
credentials {
username = project.properties["repo.credentials.private.username"].toString()
password = project.properties["repo.credentials.private.password"].toString()
}
username = project.properties["repo.credentials.self-git.username"].toString()
password = project.properties["repo.credentials.self-git.password"].toString()
}
}
}

View File

@ -3,7 +3,8 @@ package net.lamgc.scalabot.config
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.repository.Authentication
import org.eclipse.aether.repository.Proxy
import org.telegram.telegrambots.meta.ApiConstants
import org.telegram.telegrambots.meta.TelegramUrl
import java.net.URI
import java.net.URL
/**
@ -26,8 +27,22 @@ data class BotAccount(
get() = token.substringBefore(":").toLong()
}
val defaultTelegramApiUrl: String = URL(
TelegramUrl.DEFAULT_URL.schema,
TelegramUrl.DEFAULT_URL.host,
TelegramUrl.DEFAULT_URL.port,
"/"
).toExternalForm()
/**
* 机器人配置.
*
* 使用 Gson 解析时, 请添加以下类型适配器:
* - [net.lamgc.scalabot.config.serializer.ProxyTypeSerializer]
* - [net.lamgc.scalabot.config.serializer.BotConfigSerializer]
* - [net.lamgc.scalabot.config.serializer.BotAccountSerializer]
* - [net.lamgc.scalabot.config.serializer.ArtifactSerializer]
*
* @property enabled 是否启用机器人.
* @property account 机器人帐号信息, 用于访问 API.
* @property disableBuiltInAbility 是否禁用 AbilityBot 自带命令.
@ -49,8 +64,22 @@ data class BotConfig(
*/
val extensions: Set<Artifact> = emptySet(),
val proxy: ProxyConfig = ProxyConfig(type = ProxyType.NO_PROXY),
val baseApiUrl: String = ApiConstants.BASE_URL
)
val baseApiUrl: String = defaultTelegramApiUrl
) {
fun getBaseApiTelegramUrl(): TelegramUrl {
if (this.baseApiUrl == defaultTelegramApiUrl) {
return TelegramUrl.DEFAULT_URL
} else {
URI.create(baseApiUrl).let {
return TelegramUrl.builder()
.host(it.host)
.port(it.port)
.schema(it.scheme)
.build()
}
}
}
}
/**
* 代理类型.
@ -72,8 +101,16 @@ enum class ProxyType {
data class ProxyConfig(
val type: ProxyType = ProxyType.NO_PROXY,
val host: String = "127.0.0.1",
val port: Int = 1080
)
val port: Int = 1080,
) {
override fun toString(): String {
return if (type != ProxyType.NO_PROXY) {
"$type://$host:$port"
} else {
"NO_PROXY"
}
}
}
/**
* ScalaBot 的运行指标公开配置.
@ -118,6 +155,13 @@ data class MavenRepositoryConfig(
* ScalaBot App 配置.
*
* App 配置信息与 BotConfig 分开, 分别存储在各自单独的文件中.
*
* 使用 Gson 解析时, 请添加以下类型适配器:
* - [net.lamgc.scalabot.config.serializer.ProxyTypeSerializer]
* - [net.lamgc.scalabot.config.serializer.MavenRepositoryConfigSerializer]
* - [net.lamgc.scalabot.config.serializer.AuthenticationSerializer]
* - [net.lamgc.scalabot.config.serializer.UsernameAuthenticatorSerializer]
*
* @property proxy Telegram API 代理配置.
* @property metrics 运行指标数据配置. 可通过时序数据库记录运行数据.
* @property mavenRepositories Maven 远端仓库配置.

View File

@ -3,6 +3,7 @@ package net.lamgc.scalabot.config.serializer
import com.google.gson.*
import com.google.gson.reflect.TypeToken
import net.lamgc.scalabot.config.*
import net.lamgc.scalabot.config.serializer.SerializeUtils.getPrimitiveValueOrThrow
import org.eclipse.aether.artifact.AbstractArtifact
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.artifact.DefaultArtifact
@ -12,6 +13,7 @@ import org.eclipse.aether.util.repository.AuthenticationBuilder
import java.lang.reflect.Type
import java.net.MalformedURLException
import java.net.URL
import java.util.regex.Pattern
object ProxyTypeSerializer : JsonDeserializer<ProxyType>,
JsonSerializer<ProxyType> {
@ -81,8 +83,8 @@ object AuthenticationSerializer : JsonDeserializer<Authentication> {
if (json !is JsonObject) {
throw JsonParseException("Unsupported JSON type.")
}
val username = SerializerUtils.checkJsonKey(json, "username")
val password = SerializerUtils.checkJsonKey(json, "password")
val username = json.getPrimitiveValueOrThrow("username").asString
val password = json.getPrimitiveValueOrThrow("password").asString
val builder = AuthenticationBuilder()
builder.addUsername(username)
builder.addPassword(password)
@ -91,14 +93,14 @@ object AuthenticationSerializer : JsonDeserializer<Authentication> {
}
private object SerializerUtils {
fun checkJsonKey(json: JsonObject, key: String): String {
if (!json.has(key)) {
throw JsonParseException("Required field does not exist: $key")
} else if (!json.get(key).isJsonPrimitive) {
throw JsonParseException("Wrong field `$key` type: ${json.get(key)::class.java}")
internal object SerializeUtils {
fun JsonObject.getPrimitiveValueOrThrow(fieldName: String): JsonPrimitive {
val value = get(fieldName) ?: throw JsonParseException("Missing `$fieldName` field.")
if (value !is JsonPrimitive) {
throw JsonParseException("Invalid `account` field type.")
}
return json.get(key).asString
return value
}
}
@ -114,7 +116,7 @@ object MavenRepositoryConfigSerializer
is JsonObject -> {
MavenRepositoryConfig(
id = json.get("id")?.asString,
url = URL(SerializerUtils.checkJsonKey(json, "url")),
url = URL(json.getPrimitiveValueOrThrow("url").asString),
proxy = if (json.has("proxy"))
context.deserialize<Proxy>(
json.get("proxy"), Proxy::class.java
@ -260,3 +262,39 @@ object BotConfigSerializer : JsonSerializer<BotConfig>, JsonDeserializer<BotConf
}
}
object BotAccountSerializer : JsonDeserializer<BotAccount> {
private val tokenCheckRegex = Pattern.compile("\\d+:[a-zA-Z\\d_-]{35}")
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): BotAccount {
if (json == null || json.isJsonNull) {
throw JsonParseException("Missing `account` field.")
} else if (!json.isJsonObject) {
throw JsonParseException("Invalid `account` field type.")
}
val jsonObj = json.asJsonObject
val name = jsonObj.getPrimitiveValueOrThrow("name").asString
val token = jsonObj.getPrimitiveValueOrThrow("token").asString.let {
if (it.isEmpty()) {
throw JsonParseException("`token` cannot be empty.")
} else if (!tokenCheckRegex.matcher(it).matches()) {
throw JsonParseException("`token` is invalid.")
} else {
it
}
}
val creatorId = try {
jsonObj.getPrimitiveValueOrThrow("creatorId").asLong
} catch (e: NumberFormatException) {
throw JsonParseException("`creatorId` must be a number.")
}.apply {
if (this < 0) {
throw JsonParseException("`creatorId` must be a positive number.")
}
}
return BotAccount(name, token, creatorId)
}
}

View File

@ -219,6 +219,12 @@ internal class ProxyConfigTest {
assertEquals(8080, actualConfig.port)
assertEquals(ProxyType.HTTP, actualConfig.type)
}
@Test
fun `toString test`() {
assertEquals("NO_PROXY", ProxyConfig(ProxyType.NO_PROXY).toString())
assertEquals("HTTP://example.org:1008", ProxyConfig(ProxyType.HTTP, "example.org", 1008).toString())
}
}
internal class MetricsConfigTest {

View File

@ -5,6 +5,7 @@ import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import net.lamgc.scalabot.config.*
import net.lamgc.scalabot.config.serializer.SerializeUtils.getPrimitiveValueOrThrow
import org.eclipse.aether.artifact.Artifact
import org.eclipse.aether.artifact.DefaultArtifact
import org.eclipse.aether.repository.Authentication
@ -12,54 +13,39 @@ import org.eclipse.aether.repository.AuthenticationContext
import org.eclipse.aether.repository.Proxy
import org.intellij.lang.annotations.Language
import org.junit.jupiter.api.Assertions.assertThrows
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Type
import java.net.URL
import kotlin.test.*
internal class SerializersKtTest {
private val instance: Any
private val method: Method
init {
val clazz = Class.forName("net.lamgc.scalabot.config.serializer.SerializerUtils")
method = clazz.getDeclaredMethod("checkJsonKey", JsonObject::class.java, String::class.java)
method.isAccessible = true
instance = clazz.getDeclaredField("INSTANCE").apply {
isAccessible = true
}.get(null)
}
private fun invoke(json: JsonObject, key: String): String {
try {
return method.invoke(instance, json, key) as String
} catch (e: InvocationTargetException) {
throw e.targetException
}
}
internal class SerializeUtilsTest {
@Test
fun `Json key checker test`() {
fun `getPrimitiveValueOrThrow test`() {
assertThrows(JsonParseException::class.java) {
invoke(JsonObject(), "NOT_EXIST_KEY")
}
assertThrows(JsonParseException::class.java) {
invoke(JsonObject().apply { add("NULL_KEY", JsonNull.INSTANCE) }, "NULL_KEY")
}
assertThrows(JsonParseException::class.java) {
invoke(JsonObject().apply { add("ARRAY_KEY", JsonArray()) }, "ARRAY_KEY")
}
assertThrows(JsonParseException::class.java) {
invoke(JsonObject().apply { add("OBJECT_KEY", JsonObject()) }, "OBJECT_KEY")
JsonObject().getPrimitiveValueOrThrow("NOT_EXIST_KEY")
}
val expectKey = "TEST"
val expectString = "testString"
val json = JsonObject().apply { addProperty(expectKey, expectString) }
assertThrows(JsonParseException::class.java) {
JsonObject().apply {
add("testKey", JsonArray())
}.getPrimitiveValueOrThrow("testKey")
}
assertThrows(JsonParseException::class.java) {
JsonObject().apply {
add("testKey", JsonObject())
}.getPrimitiveValueOrThrow("testKey")
}
assertThrows(JsonParseException::class.java) {
JsonObject().apply {
add("testKey", JsonNull.INSTANCE)
}.getPrimitiveValueOrThrow("testKey")
}
assertEquals(expectString, invoke(json, expectKey))
val expectKey = "STRING_KEY"
val expectValue = JsonPrimitive("A STRING")
assertEquals(expectValue, JsonObject()
.apply { add(expectKey, expectValue) }
.getPrimitiveValueOrThrow(expectKey))
}
}
@ -67,7 +53,7 @@ internal class ProxyTypeSerializerTest {
@Test
fun `serialize test`() {
for (type in ProxyType.values()) {
for (type in ProxyType.entries) {
assertEquals(
JsonPrimitive(type.name), ProxyTypeSerializer.serialize(type, null, null),
"ProxyType 序列化结果与预期不符."
@ -93,7 +79,7 @@ internal class ProxyTypeSerializerTest {
ProxyTypeSerializer.deserialize(JsonNull.INSTANCE, null, null)
)
for (type in ProxyType.values()) {
for (type in ProxyType.entries) {
assertEquals(
type, ProxyTypeSerializer.deserialize(JsonPrimitive(type.name), null, null),
"ProxyType 反序列化结果与预期不符."
@ -706,3 +692,161 @@ internal class UsernameAuthenticatorSerializerTest {
}
}
internal class BotAccountSerializerTest {
private val expectToken = "123456789:AAHErDroUTznQsOd_oZPJ6cQEj4Z5mGHO10"
private val gson = GsonBuilder()
.registerTypeAdapter(BotAccount::class.java, BotAccountSerializer)
.create()
@Test
fun `Invalid json type check test`() {
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(null, null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonNull.INSTANCE, null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonPrimitive("A STRING"), null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonArray(), null, null)
}
}
@Test
fun `Field missing test`() {
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonObject(), null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonObject().apply {
addProperty("token", expectToken)
addProperty("creatorId", 1)
}, null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonObject().apply {
addProperty("name", "testUser")
addProperty("creatorId", 1)
}, null, null)
}
assertThrows(JsonParseException::class.java) {
BotAccountSerializer.deserialize(JsonObject().apply {
addProperty("name", "testUser")
addProperty("token", expectToken)
}, null, null)
}
val account = BotAccountSerializer.deserialize(JsonObject().apply {
addProperty("name", "testUser")
addProperty("token", expectToken)
addProperty("creatorId", 1)
}, null, null)
assertNotNull(account)
assertEquals("testUser", account.name)
assertEquals(expectToken, account.token)
assertEquals(1, account.creatorId)
}
@Test
fun `'token' check test`() {
val jsonObject = JsonObject().apply {
addProperty("name", "testUser")
addProperty("token", expectToken)
addProperty("creatorId", 123456789123456789)
}
val looksGoodAccount = BotAccountSerializer.deserialize(jsonObject, null, null)
assertNotNull(looksGoodAccount)
assertEquals("testUser", looksGoodAccount.name)
assertEquals(expectToken, looksGoodAccount.token)
assertEquals(123456789123456789, looksGoodAccount.creatorId)
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("token", "")
}, null, null)
fail("Token 为空,但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`token` cannot be empty.", e.message)
}
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("token", "abcdefghijklmnopqrstuvwxyz")
}, null, null)
fail("Token 格式错误(基本格式错误),但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`token` is invalid.", e.message)
}
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("token", "abcdefgh:ijklmnopqrstuvwxyz-1234567890_abcde")
}, null, null)
fail("Token 格式错误ID 不为数字),但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`token` is invalid.", e.message)
}
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("token", "0123456789:ijklmnopqrstu-vwxyz_123456")
}, null, null)
fail("Token 格式错误(授权令牌长度错误),但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`token` is invalid.", e.message)
}
}
@Test
fun `'creatorId' check test`() {
val jsonObject = JsonObject().apply {
addProperty("name", "testUser")
addProperty("token", expectToken)
addProperty("creatorId", 1)
}
val looksGoodAccount = gson.fromJson(jsonObject, BotAccount::class.java)
assertEquals(1, looksGoodAccount.creatorId)
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("creatorId", "A STRING")
}, null, null)
fail("creatorId 不是一个数字,但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`creatorId` must be a number.", e.message)
}
try {
BotAccountSerializer.deserialize(jsonObject.deepCopy().apply {
addProperty("creatorId", -1)
}, null, null)
fail("creatorId 不能为负数,但是没有抛出异常。")
} catch (e: JsonParseException) {
assertEquals("`creatorId` must be a positive number.", e.message)
}
}
@Test
fun `json deserialize test`() {
val jsonObject = JsonObject().apply {
addProperty("name", "testUser")
addProperty("token", expectToken)
addProperty("creatorId", 1)
}
val looksGoodAccount = gson.fromJson(jsonObject, BotAccount::class.java)
assertNotNull(looksGoodAccount)
assertEquals("testUser", looksGoodAccount.name)
assertEquals(expectToken, looksGoodAccount.token)
assertEquals(1, looksGoodAccount.creatorId)
}
}