mirror of
https://github.com/TheWhiteDog9487/WebAPI.git
synced 2026-08-11 14:51:30 +08:00
支持不提供Discord令牌启动服务
重整代码内的Swagger排版 代码格式优化
This commit is contained in:
@@ -8,6 +8,14 @@
|
||||
能用,但缺的东西非常多。
|
||||
就像这个文档一样。
|
||||
|
||||
# 命令行参数
|
||||
| 参数 | 说明 |
|
||||
|---|------------------------------------------------------------|
|
||||
| `install` / `--install` | 安装为 systemd 服务 |
|
||||
| `uninstall` / `--uninstall` | 卸载 systemd 服务 |
|
||||
| `--Discord_Bot_Token <令牌>` | 设置 Discord 机器人令牌,优先级高于同名环境变量 |
|
||||
| `--Disable-Discord` | 安装systemd服务时禁用 Discord 相关功能,故不再要求提供令牌 |
|
||||
|
||||
# 注意事项
|
||||
**本项目不保证配置文件和环境变量的向后兼容!!!**
|
||||
**也就是说,如果你也要用的话,你可能必须在更新之后重新配置环境变量和配置文件**
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ plugins {
|
||||
}
|
||||
|
||||
group = "xyz.thewhitedog9487"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
|
||||
@@ -21,7 +21,7 @@ class OpenApiConfiguration {
|
||||
.contact(Contact()
|
||||
.name("TheWhiteDog9487")
|
||||
.url("https://www.github.com/TheWhiteDog9487/WebAPI"))
|
||||
.version("0.8.2")
|
||||
.version("0.8.3")
|
||||
.license(License()
|
||||
.name("WTFPL")
|
||||
.url("https://spdx.org/licenses/WTFPL")) )
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import xyz.thewhitedog9487.WebAPI.Data.Entity.AccessLog
|
||||
import xyz.thewhitedog9487.WebAPI.Miscellaneous.SpringContextHolder.SpringContext
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class ApiKeyAuthenticationFilter(): OncePerRequestFilter() {
|
||||
class ApiKeyAuthenticationFilter: OncePerRequestFilter() {
|
||||
val ApiKeyManagerInstance = SpringContext.getBean<ApiKeyManager>()
|
||||
|
||||
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
|
||||
|
||||
@@ -41,22 +41,18 @@ class AccessLog(val AccessLogRepositoryInstance: AccessLogRepository) {
|
||||
examples = [
|
||||
ExampleObject(
|
||||
name = "Limit小于0",
|
||||
value = """
|
||||
{
|
||||
value = """{
|
||||
"code": 400,
|
||||
"message": "Limit参数不能小于0",
|
||||
"data": null
|
||||
}
|
||||
""" ),
|
||||
}""" ),
|
||||
ExampleObject(
|
||||
name = "字段不存在",
|
||||
value = """
|
||||
{
|
||||
value = """{
|
||||
"code": 400,
|
||||
"message": "试图访问一个不存在的数据库字段",
|
||||
"data": "AccessLog类中不存在名为 NotExistField 的字段"
|
||||
}
|
||||
""" ) ] ) ] ),
|
||||
}""" ) ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "成功获取到数据",
|
||||
@@ -68,8 +64,7 @@ class AccessLog(val AccessLogRepositoryInstance: AccessLogRepository) {
|
||||
schema = Schema(implementation = AccessLog::class) ),
|
||||
examples = [
|
||||
ExampleObject(
|
||||
value = """
|
||||
[
|
||||
value = """[
|
||||
{
|
||||
"ID": 18,
|
||||
"RequestID": "3",
|
||||
@@ -105,27 +100,8 @@ class AccessLog(val AccessLogRepositoryInstance: AccessLogRepository) {
|
||||
"Header": "host: dev.thewhitedog9487.xyz\nx-real-ip: 172.71.150.157\nx-forwarded-for: 2409:8962:77a:49c:a579:f5af:58a3:e2c, 172.71.150.157\nx-forwarded-proto: https\nconnection: close\nx-api-key: asdasdaFSEA452453sdcv\nuser-agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.2.3\naccept: */*\ncf-ray: 98cc7d6aaea1c37a-SEA\naccept-encoding: gzip, br\ncdn-loop: cloudflare; loops=1\ncf-connecting-ip: 2409:8962:77a:49c:a579:f5af:58a3:e2c\ncf-ipcountry: CN\ncf-visitor: {\"scheme\":\"https\"}\ncookie: JSESSIONID=A49527B913170D86A5544A252BD31040",
|
||||
"Timestamp": "2025-10-11T07:02:05.718Z",
|
||||
"ResponseStatusCode": 200
|
||||
},
|
||||
{
|
||||
"ID": 263,
|
||||
"RequestID": "35",
|
||||
"CF_Connecting_IP": "2409:8962:77a:49c:a579:f5af:58a3:e2c",
|
||||
"X_Forwarded_For": "2409:8962:77a:49c:a579:f5af:58a3:e2c, 108.162.246.209",
|
||||
"RemoteAddress": "192.168.128.11",
|
||||
"CF_IPCountry": "CN",
|
||||
"ISO3166": "CHN",
|
||||
"UserAgent": "IntelliJ HTTP Client/IntelliJ IDEA 2025.2.3",
|
||||
"HttpMethod": "GET",
|
||||
"Protocol": "http",
|
||||
"ProtocolVersion": "HTTP/1.0",
|
||||
"URL": "http://dev.thewhitedog9487.xyz/ip/ip",
|
||||
"QueryString": null,
|
||||
"Header": "host: dev.thewhitedog9487.xyz\nx-real-ip: 108.162.246.209\nx-forwarded-for: 2409:8962:77a:49c:a579:f5af:58a3:e2c, 108.162.246.209\nx-forwarded-proto: https\nconnection: close\naccept-encoding: gzip, br\nuser-agent: IntelliJ HTTP Client/IntelliJ IDEA 2025.2.3\naccept: */*\ncf-ray: 98cc9ec12c48a1a5-SEA\ncdn-loop: cloudflare; loops=1\ncf-connecting-ip: 2409:8962:77a:49c:a579:f5af:58a3:e2c\ncf-ipcountry: CN\ncf-visitor: {\"scheme\":\"https\"}\ncookie: JSESSIONID=A49527B913170D86A5544A252BD31040",
|
||||
"Timestamp": "2025-10-11T07:24:51.504Z",
|
||||
"ResponseStatusCode": 200
|
||||
}
|
||||
]
|
||||
""" ) ] ) ] ),
|
||||
]""" ) ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "未提供API密钥",
|
||||
@@ -135,13 +111,11 @@ class AccessLog(val AccessLogRepositoryInstance: AccessLogRepository) {
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [
|
||||
ExampleObject(
|
||||
value = """
|
||||
{
|
||||
value = """{
|
||||
"code": 401,
|
||||
"message": "API密钥验证失败,未传递X-API-Key请求头",
|
||||
"data": null
|
||||
}
|
||||
""" ) ] ) ] ),
|
||||
}""" ) ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "API密钥无效",
|
||||
@@ -151,13 +125,11 @@ class AccessLog(val AccessLogRepositoryInstance: AccessLogRepository) {
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [
|
||||
ExampleObject(
|
||||
value = """
|
||||
{
|
||||
value = """{
|
||||
"code": 403,
|
||||
"message": "API密钥验证失败,API密钥无效",
|
||||
"data": null
|
||||
}
|
||||
""" ) ] ) ] ) ] )
|
||||
}""" ) ] ) ] ) ] )
|
||||
@GetMapping
|
||||
fun GetLog(@Parameter(description = "用于身份验证的API密钥", `in` = ParameterIn.HEADER, required = true, example = "ds1858dscc8745sfwe" )
|
||||
@RequestHeader("X-API-Key") ApiKey: String,
|
||||
|
||||
@@ -26,12 +26,13 @@ class IP {
|
||||
1. CF-Connecting-IP
|
||||
2. X-Forwarded-For
|
||||
3. 直接使用请求的远程地址""")
|
||||
@ApiResponse(responseCode = "200",
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "成功获取到IP地址,内容为纯文本格式的IP地址",
|
||||
content = [Content(
|
||||
mediaType = MediaType.TEXT_PLAIN_VALUE,
|
||||
schema = Schema(implementation = String::class),
|
||||
examples = [ExampleObject(value = "78.141.226.247")])],
|
||||
description = "成功获取到IP地址,内容为纯文本格式的IP地址")
|
||||
examples = [ExampleObject(value = "78.141.226.247") ] ) ] )
|
||||
@GetMapping("")
|
||||
fun GetIP(@RequestHeader("CF-Connecting-IP", required = false) Header_CFConnectingIP: String?,
|
||||
@RequestHeader("X-Forwarded-For", required = false) Header_XForwardedFor: String?,
|
||||
@@ -54,18 +55,20 @@ class IP {
|
||||
如果请求没有经过Cloudflare,则会返回"未找到CF-IPCountry头部"
|
||||
""")
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "200",
|
||||
ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "成功获取到ISO 3166-1 alpha-2国家代码,内容为纯文本格式的国家代码",
|
||||
content = [Content(
|
||||
mediaType = MediaType.TEXT_PLAIN_VALUE,
|
||||
schema = Schema(implementation = String::class),
|
||||
examples = [ExampleObject(value = "HK")])],
|
||||
description = "成功获取到ISO 3166-1 alpha-2国家代码,内容为纯文本格式的国家代码"),
|
||||
ApiResponse(responseCode = "404",
|
||||
examples = [ExampleObject(value = "HK") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "未找到CF-IPCountry头部,内容为纯文本格式的错误信息",
|
||||
content = [Content(
|
||||
mediaType = MediaType.TEXT_PLAIN_VALUE,
|
||||
schema = Schema(implementation = String::class),
|
||||
examples = [ExampleObject(value = "未找到CF-IPCountry头部")] ) ],
|
||||
description = "未找到CF-IPCountry头部,内容为纯文本格式的错误信息") ] )
|
||||
examples = [ExampleObject(value = "未找到CF-IPCountry头部") ] ) ] ) ] )
|
||||
@GetMapping("iso3166")
|
||||
fun GetIso3166(@RequestHeader("CF-IPCountry", required = false) Header_CFIPCountry: String?): ResponseEntity<String> {
|
||||
Header_CFIPCountry?.let {
|
||||
|
||||
@@ -20,8 +20,8 @@ import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||
import org.springframework.web.bind.MissingRequestHeaderException
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import xyz.thewhitedog9487.WebAPI.Exception.DiscordBotTokenDoesNotConfiguredException
|
||||
import xyz.thewhitedog9487.WebAPI.Exception.NoSuchDiscordChannelException
|
||||
import xyz.thewhitedog9487.WebAPI.Miscellaneous.VirtualThreadCoroutineDispatcher
|
||||
import xyz.thewhitedog9487.WebAPI.Miscellaneous.link
|
||||
@@ -30,7 +30,7 @@ import java.net.URI
|
||||
@Tag(name="远程消息处理相关")
|
||||
@RestController
|
||||
@RequestMapping("/message")
|
||||
class Message(val DiscordBotClient: Kord) {
|
||||
class Message(val DiscordBotClient: Kord?) {
|
||||
@JsonAutoDetect(
|
||||
fieldVisibility = JsonAutoDetect.Visibility.ANY,
|
||||
getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
@@ -51,92 +51,97 @@ class Message(val DiscordBotClient: Kord) {
|
||||
需要在请求头中提供X-API-Key以进行身份验证
|
||||
需要在请求体中提供频道ID和消息内容""")
|
||||
@ApiResponses(value = [
|
||||
ApiResponse(responseCode = "201",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value =
|
||||
"""
|
||||
{
|
||||
"code": 201,
|
||||
"message": "消息发送成功",
|
||||
"data": {
|
||||
"新ID": "1407848258813825135",
|
||||
"频道ID": "1398192763845214239",
|
||||
"内容": "写点什么好呢"
|
||||
}
|
||||
}
|
||||
""", name = "成功") ] ) ],
|
||||
description = "消息发送成功,响应体中包含新消息的ID、频道ID和内容"),
|
||||
ApiResponse(responseCode = "400",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value =
|
||||
"""
|
||||
{
|
||||
"code": 400,
|
||||
"message": "请求体无法解析",
|
||||
"data": {
|
||||
"错误信息": "JSON parse error: Unexpected character ('}' (code 125)): was expecting double-quote to start field name"
|
||||
}
|
||||
}
|
||||
""", name = "请求体无法解析"),
|
||||
ExampleObject(value =
|
||||
"""
|
||||
{
|
||||
"code": 400,
|
||||
"message": "消息发送失败",
|
||||
"data": {
|
||||
"错误信息": "ID为1398192763845214239的频道不存在",
|
||||
"频道ID": "1398192763845214239"
|
||||
}
|
||||
}
|
||||
""", name = "频道不存在")] ) ],
|
||||
description = "客户端发送的请求存在问题,请检查响应的data字段以获取更多信息"),
|
||||
ApiResponse(responseCode = "401",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value =
|
||||
"""
|
||||
{
|
||||
"code": 401,
|
||||
"message": "API密钥验证失败,未传递X-API-Key请求头",
|
||||
"data": null
|
||||
}
|
||||
""") ] ) ],
|
||||
description = "未提供API密钥"),
|
||||
ApiResponse(responseCode = "403",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value =
|
||||
"""
|
||||
{
|
||||
"code": 403,
|
||||
"message": "API密钥验证失败,API密钥无效",
|
||||
"data": null
|
||||
}
|
||||
""") ] ) ],
|
||||
description = "API密钥无效"),
|
||||
ApiResponse(responseCode = "500",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value =
|
||||
"""{
|
||||
"code": 500,
|
||||
"message": "处理请求时发生未知错误",
|
||||
"data": {
|
||||
"错误信息": "POST /channels/1398192763845214/messages returned 404 Not Found with response {code=10003, message=Unknown Channel}"
|
||||
}
|
||||
}""", name = "未知错误") ] ) ],
|
||||
ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "消息发送成功,响应体中包含新消息的ID、频道ID和内容",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value = """{
|
||||
"code": 201,
|
||||
"message": "消息发送成功",
|
||||
"data": {
|
||||
"新ID": "1407848258813825135",
|
||||
"频道ID": "1398192763845214239",
|
||||
"内容": "写点什么好呢"
|
||||
}
|
||||
}""") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "400",
|
||||
description = "客户端发送的请求存在问题,请检查响应的data字段以获取更多信息",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(
|
||||
name = "请求体无法解析",
|
||||
value = """{
|
||||
"code": 400,
|
||||
"message": "请求体无法解析",
|
||||
"data": {
|
||||
"错误信息": "JSON parse error: Unexpected character ('}' (code 125)): was expecting double-quote to start field name"
|
||||
}
|
||||
}"""),
|
||||
ExampleObject(
|
||||
name = "频道不存在",
|
||||
value =
|
||||
"""{
|
||||
"code": 400,
|
||||
"message": "消息发送失败",
|
||||
"data": {
|
||||
"错误信息": "ID为1398192763845214239的频道不存在",
|
||||
"频道ID": "1398192763845214239"
|
||||
}
|
||||
}""") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "401",
|
||||
description = "未提供API密钥",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value = """{
|
||||
"code": 401,
|
||||
"message": "API密钥验证失败,未传递X-API-Key请求头",
|
||||
"data": null
|
||||
}""") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "403",
|
||||
description = "API密钥无效",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value = """{
|
||||
"code": 403,
|
||||
"message": "API密钥验证失败,API密钥无效",
|
||||
"data": null
|
||||
}""") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "503",
|
||||
description = "服务端未配置Discord令牌,无法使用Discord相关功能",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value = """{
|
||||
"code": 503,
|
||||
"message": "服务端尚未配置Discord令牌,无法使用Discord相关功能!",
|
||||
"data": null
|
||||
}""") ] ) ] ),
|
||||
ApiResponse(
|
||||
responseCode = "500",
|
||||
description =
|
||||
"""
|
||||
"""
|
||||
处理请求时发生未知错误,可能是由于Discord服务器问题或其他内部错误,请查看响应Body以确定原因
|
||||
另外,所有未被针对性处理的异常都会触发此响应
|
||||
""") ] )
|
||||
""",
|
||||
content = [Content(
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = ResponseData::class),
|
||||
examples = [ExampleObject(value = """{
|
||||
"code": 500,
|
||||
"message": "处理请求时发生未知错误",
|
||||
"data": {
|
||||
"错误信息": "POST /channels/1398192763845214/messages returned 404 Not Found with response {code=10003, message=Unknown Channel}"
|
||||
}
|
||||
}""") ] ) ] ) ] )
|
||||
@PostMapping("/discord")
|
||||
suspend fun DiscordPush(
|
||||
@Parameter(description = "用于身份验证的API密钥", `in` = ParameterIn.HEADER, required = true, example = "ds1858dscc8745sfwe")
|
||||
@@ -148,9 +153,10 @@ class Message(val DiscordBotClient: Kord) {
|
||||
mediaType = MediaType.APPLICATION_JSON_VALUE,
|
||||
schema = Schema(implementation = PostMessageData::class) ) ] )
|
||||
@RequestBody RequestBody: PostMessageData): ResponseEntity<ResponseData> {
|
||||
DiscordBotClient ?: throw DiscordBotTokenDoesNotConfiguredException()
|
||||
return withContext(VirtualThreadCoroutineDispatcher) {
|
||||
val ChannelID = Snowflake(RequestBody.ChannelId)
|
||||
val MessageData = DiscordBotClient
|
||||
val MessageData = DiscordBotClient!!
|
||||
.getChannelOf<TextChannel>(ChannelID)
|
||||
?.createMessage(RequestBody.Content)
|
||||
?: throw NoSuchDiscordChannelException(ChannelID)
|
||||
@@ -162,6 +168,13 @@ class Message(val DiscordBotClient: Kord) {
|
||||
"新ID" to MessageData.id.toString(),
|
||||
"频道ID" to ChannelID.value,
|
||||
"内容" to RequestBody.Content ) ) ) } }
|
||||
|
||||
@ExceptionHandler(DiscordBotTokenDoesNotConfiguredException::class)
|
||||
fun TriggerWhenDiscordBotTokenDoesNotConfigured(Exception: DiscordBotTokenDoesNotConfiguredException, Request: HttpServletRequest): ResponseEntity<ResponseData> {
|
||||
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
|
||||
.body(ResponseData(
|
||||
HttpStatus.SERVICE_UNAVAILABLE.value(),
|
||||
Exception.message ) ) }
|
||||
@ExceptionHandler(NoSuchDiscordChannelException::class)
|
||||
fun TriggerWhenSpecificChannelDoesNotExist(Exception: NoSuchDiscordChannelException, Request: HttpServletRequest): ResponseEntity<ResponseData> {
|
||||
return ResponseEntity.badRequest()
|
||||
@@ -171,13 +184,6 @@ class Message(val DiscordBotClient: Kord) {
|
||||
mapOf(
|
||||
"错误信息" to Exception.message,
|
||||
"频道ID" to Exception.TargetChannelId.value ) ) ) }
|
||||
@ExceptionHandler(MissingRequestHeaderException::class)
|
||||
fun HandleMissingHeader(Exception: MissingRequestHeaderException, Request: HttpServletRequest): ResponseEntity<ResponseData> {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(ResponseData(
|
||||
HttpStatus.BAD_REQUEST.value(),
|
||||
"请求缺少必要的头部信息",
|
||||
mapOf("缺失的头部" to Exception.headerName ) ) ) }
|
||||
@ExceptionHandler(HttpMessageNotReadableException::class)
|
||||
fun HandleMessageNotReadable(Exception: HttpMessageNotReadableException, Request: HttpServletRequest): ResponseEntity<ResponseData> {
|
||||
return ResponseEntity.badRequest()
|
||||
|
||||
@@ -105,7 +105,7 @@ cookie: JSESSIONID=A49527B913170D86A5544A252BD31040
|
||||
var Header: String = "",
|
||||
|
||||
@JsonProperty("Timestamp")
|
||||
@Schema(description = "请求时间(ISO-8601格式)", example = "2025-09-29T03:49:42.766Z")
|
||||
@Schema(description = "请求时间 ISO-8601格式", example = "2025-09-29T03:49:42.766Z")
|
||||
var Timestamp: Instant = Instant.now(),
|
||||
|
||||
@JsonProperty("ResponseStatusCode")
|
||||
@@ -126,11 +126,11 @@ cookie: JSESSIONID=A49527B913170D86A5544A252BD31040
|
||||
httpRequest.requestURL.toString(),
|
||||
httpRequest.queryString,
|
||||
httpRequest.headerNames.toList().joinToString("\n") { name ->
|
||||
return@joinToString "$name: ${httpRequest.getHeaders(name).toList().joinToString(", ")}" },
|
||||
return@joinToString "$name: ${httpRequest.getHeaders(name).toList().joinToString(", ") }" },
|
||||
Instant.now(),
|
||||
0 )
|
||||
fun SaveIntoDatabase(CachedResponse: ContentCachingResponseWrapper? = null){
|
||||
val SQLiteWriteLock = SpringContext.getBean("getSQLiteWriteLock", ReentrantLock::class.java)
|
||||
val SQLiteWriteLock = SpringContext.getBean<ReentrantLock>("SQLiteWriteLock")
|
||||
val AccessLogRepository = SpringContext.getBean<AccessLogRepository>()
|
||||
try {
|
||||
SQLiteWriteLock.lock()
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
package xyz.thewhitedog9487.WebAPI.Exception
|
||||
|
||||
class DiscordBotTokenDoesNotConfiguredException: Exception("服务端尚未配置Discord令牌,无法使用Discord相关功能!")
|
||||
@@ -20,27 +20,27 @@ class GlobalSharedBean {
|
||||
val Logger = KotlinLogging.logger{}
|
||||
|
||||
@Bean
|
||||
fun DiscordClient(@Value("\${Discord_Bot_Token:}") DiscordBotToken: String): Kord {
|
||||
fun DiscordClient(@Value("\${Discord_Bot_Token:}") DiscordBotToken: String): Kord? {
|
||||
if (DiscordBotToken.isEmpty()) {
|
||||
Logger.error { "未通过参数--Discord_Bot_Token或环境变量Discord_Bot_Token提供Discord登录令牌,请检查配置。" }
|
||||
throw IllegalArgumentException("未提供Discord登录令牌") }
|
||||
Logger.warn { "未通过参数--Discord_Bot_Token或环境变量Discord_Bot_Token提供Discord登录令牌,将无法使用Discord相关功能。" }
|
||||
return null }
|
||||
return runBlocking(VirtualThreadCoroutineDispatcher) { Kord(DiscordBotToken) } }
|
||||
|
||||
@Bean
|
||||
fun KordLifecycleManager(KordInstance: Kord) = object: SmartLifecycle {
|
||||
fun KordLifecycleManager(KordInstance: Kord?) = object: SmartLifecycle {
|
||||
var Job: Job? = null
|
||||
override fun start() {
|
||||
Job = CoroutineScope(VirtualThreadCoroutineDispatcher).launch {
|
||||
KordInstance.login { } } }
|
||||
KordInstance?.login { } } }
|
||||
|
||||
override fun stop() {
|
||||
runBlocking(VirtualThreadCoroutineDispatcher) {
|
||||
try {
|
||||
KordInstance.logout()
|
||||
KordInstance?.logout()
|
||||
} catch (_: IllegalStateException) { }
|
||||
Job?.cancelAndJoin() } }
|
||||
|
||||
override fun isRunning() = Job?.isActive ?: false }
|
||||
|
||||
@get:Bean
|
||||
val SQLiteWriteLock: Lock = ReentrantLock() }
|
||||
@get:Bean(name = ["SQLiteWriteLock"])
|
||||
val SQLiteWriteLock: Lock = ReentrantLock() }
|
||||
|
||||
@@ -60,13 +60,16 @@ fun ProcessArguments(CommandLineArguments: Array<String>) {
|
||||
在Native Image / Jar文件旁边生成指向自身的,名为Current的软连接
|
||||
然后在软连接旁生成systemd服务文件,执行目标指向软连接
|
||||
*/
|
||||
val DisableDiscord = "--Disable-Discord" in CommandLineArguments
|
||||
val DiscordBotToken = if ("--Discord_Bot_Token" in CommandLineArguments &&
|
||||
CommandLineArguments.getOrNull(CommandLineArguments.indexOf("--Discord_Bot_Token") + 1) != null ){
|
||||
CommandLineArguments[CommandLineArguments.indexOf("--Discord_Bot_Token") + 1] }
|
||||
else System.getenv().getOrDefault("Discord_Bot_Token", "")
|
||||
if (DiscordBotToken.isEmpty()) {
|
||||
if (DiscordBotToken.isEmpty() && DisableDiscord == false) {
|
||||
Logger.error { "必须通过--Discord_Bot_Token参数或Discord_Bot_Token环境变量提供Discord机器人的令牌以使本程序正常工作。" }
|
||||
throw IllegalArgumentException("缺少必须的--Discord_Bot_Token参数") }
|
||||
if (DisableDiscord) {
|
||||
Logger.warn { "已通过--Disable-Discord参数禁用Discord功能,程序无法使用Discord相关功能。" } }
|
||||
Logger.info { "开始安装systemd服务" }
|
||||
Logger.debug { "SystemProperties.os.name: $CurrentOS" }
|
||||
if (CurrentOS.startsWith("Linux")) {
|
||||
@@ -100,7 +103,7 @@ fun ProcessArguments(CommandLineArguments: Array<String>) {
|
||||
ExecStart=$ExecCommand
|
||||
Restart=always
|
||||
Type=simple
|
||||
Environment="Discord_Bot_Token=$DiscordBotToken"
|
||||
${if (DisableDiscord == false) "Environment=\"Discord_Bot_Token=$DiscordBotToken\"" else ""}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
Reference in New Issue
Block a user