refactor: 重构代码结构,按业务分类组织 Controller 和 Service
- 重构 API 路径为 /api/业务/xxx 格式 - 将 Controller 和 Service 按业务分类组织: * copytrading: 跟单相关(configs, leaders, statistics, templates) * accounts: 账户管理(公共模块) * markets: 市场数据(公共模块) * system: 系统管理(users, notifications, proxy, health) * auth: 认证 * announcement: 公告 - 将所有完整类名引用改为使用 import 导入 - 修复 calculatePositionValue 方法实现 - 更新前端 API 调用路径
This commit is contained in:
@@ -94,6 +94,13 @@ coverage/
|
|||||||
test-results/
|
test-results/
|
||||||
*.test.log
|
*.test.log
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
*.bak
|
*.bak
|
||||||
*.backup
|
*.backup
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ data class CreateOrderRequest(
|
|||||||
|
|
||||||
@Deprecated("使用 NewOrderRequest 代替")
|
@Deprecated("使用 NewOrderRequest 代替")
|
||||||
data class CreateOrdersBatchRequest(
|
data class CreateOrdersBatchRequest(
|
||||||
val orders: List<CreateOrderRequest>
|
val orders: List<NewOrderRequest>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CancelOrdersBatchRequest(
|
data class CancelOrdersBatchRequest(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.wrbug.polymarketbot.config
|
package com.wrbug.polymarketbot.config
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.service.ProxyConfigService
|
import com.wrbug.polymarketbot.service.system.ProxyConfigService
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.accounts
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.AccountService
|
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@@ -15,7 +15,7 @@ import java.math.BigDecimal
|
|||||||
* 账户管理控制器
|
* 账户管理控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/copy-trading/accounts")
|
@RequestMapping("/api/accounts")
|
||||||
class AccountController(
|
class AccountController(
|
||||||
private val accountService: AccountService,
|
private val accountService: AccountService,
|
||||||
private val messageSource: MessageSource
|
private val messageSource: MessageSource
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.announcement
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.AnnouncementService
|
import com.wrbug.polymarketbot.service.announcement.AnnouncementService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.auth
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.AuthService
|
import com.wrbug.polymarketbot.service.auth.AuthService
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.copytrading.configs
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.CopyTradingService
|
import com.wrbug.polymarketbot.service.copytrading.configs.CopyTradingService
|
||||||
import com.wrbug.polymarketbot.service.FilteredOrderService
|
import com.wrbug.polymarketbot.service.copytrading.configs.FilteredOrderService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* 跟单配置管理控制器(钱包-模板关联)
|
* 跟单配置管理控制器(钱包-模板关联)
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/copy-trading")
|
@RequestMapping("/api/copy-trading/configs")
|
||||||
class CopyTradingController(
|
class CopyTradingController(
|
||||||
private val copyTradingService: CopyTradingService,
|
private val copyTradingService: CopyTradingService,
|
||||||
private val filteredOrderService: FilteredOrderService,
|
private val filteredOrderService: FilteredOrderService,
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.copytrading.leaders
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.LeaderService
|
import com.wrbug.polymarketbot.service.copytrading.leaders.LeaderService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.copytrading.statistics
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.CopyTradingStatisticsService
|
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyTradingStatisticsService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.copytrading.templates
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.CopyTradingTemplateService
|
import com.wrbug.polymarketbot.service.copytrading.templates.CopyTradingTemplateService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
+4
-4
@@ -1,10 +1,10 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.markets
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.LatestPriceResponse
|
import com.wrbug.polymarketbot.api.LatestPriceResponse
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.AccountService
|
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||||
import com.wrbug.polymarketbot.service.PolymarketClobService
|
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* 提供市场相关的数据查询接口(价格、订单簿等)
|
* 提供市场相关的数据查询接口(价格、订单簿等)
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/copy-trading/markets")
|
@RequestMapping("/api/markets")
|
||||||
class MarketController(
|
class MarketController(
|
||||||
private val accountService: AccountService,
|
private val accountService: AccountService,
|
||||||
private val clobService: PolymarketClobService,
|
private val clobService: PolymarketClobService,
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.system
|
||||||
|
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
@@ -11,7 +11,7 @@ import java.util.*
|
|||||||
* 用于 Docker 健康检查和监控
|
* 用于 Docker 健康检查和监控
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/health")
|
@RequestMapping("/api/system/health")
|
||||||
class HealthController {
|
class HealthController {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.NotificationConfigService
|
import com.wrbug.polymarketbot.service.system.NotificationConfigService
|
||||||
import com.wrbug.polymarketbot.service.TelegramNotificationService
|
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* 消息推送配置控制器
|
* 消息推送配置控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/notifications")
|
@RequestMapping("/api/system/notifications")
|
||||||
class NotificationController(
|
class NotificationController(
|
||||||
private val notificationConfigService: NotificationConfigService,
|
private val notificationConfigService: NotificationConfigService,
|
||||||
private val telegramNotificationService: TelegramNotificationService,
|
private val telegramNotificationService: TelegramNotificationService,
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.ApiHealthCheckService
|
import com.wrbug.polymarketbot.service.system.ApiHealthCheckService
|
||||||
import com.wrbug.polymarketbot.service.ProxyConfigService
|
import com.wrbug.polymarketbot.service.system.ProxyConfigService
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* 代理配置控制器
|
* 代理配置控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/proxy-config")
|
@RequestMapping("/api/system/proxy")
|
||||||
class ProxyConfigController(
|
class ProxyConfigController(
|
||||||
private val proxyConfigService: ProxyConfigService,
|
private val proxyConfigService: ProxyConfigService,
|
||||||
private val apiHealthCheckService: ApiHealthCheckService,
|
private val apiHealthCheckService: ApiHealthCheckService,
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.SystemConfigService
|
import com.wrbug.polymarketbot.service.system.SystemConfigService
|
||||||
import com.wrbug.polymarketbot.service.RelayClientService
|
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
+3
-3
@@ -1,8 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.controller
|
package com.wrbug.polymarketbot.controller.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||||
import com.wrbug.polymarketbot.service.UserService
|
import com.wrbug.polymarketbot.service.system.UserService
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* 用户管理控制器
|
* 用户管理控制器
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/users")
|
@RequestMapping("/api/system/users")
|
||||||
class UserController(
|
class UserController(
|
||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val messageSource: MessageSource
|
private val messageSource: MessageSource
|
||||||
+13
-5
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.accounts
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.TradeResponse
|
import com.wrbug.polymarketbot.api.TradeResponse
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
@@ -8,6 +8,14 @@ import com.wrbug.polymarketbot.util.RetrofitFactory
|
|||||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||||
import com.wrbug.polymarketbot.util.eq
|
import com.wrbug.polymarketbot.util.eq
|
||||||
import com.wrbug.polymarketbot.util.JsonUtils
|
import com.wrbug.polymarketbot.util.JsonUtils
|
||||||
|
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||||
|
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||||
|
import com.wrbug.polymarketbot.service.common.PolymarketApiKeyService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderSigningService
|
||||||
|
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||||
|
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||||
|
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -27,7 +35,7 @@ class AccountService(
|
|||||||
private val apiKeyService: PolymarketApiKeyService,
|
private val apiKeyService: PolymarketApiKeyService,
|
||||||
private val orderPushService: OrderPushService,
|
private val orderPushService: OrderPushService,
|
||||||
private val orderSigningService: OrderSigningService,
|
private val orderSigningService: OrderSigningService,
|
||||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
private val cryptoUtils: CryptoUtils,
|
||||||
private val telegramNotificationService: TelegramNotificationService? = null, // 可选,避免循环依赖
|
private val telegramNotificationService: TelegramNotificationService? = null, // 可选,避免循环依赖
|
||||||
private val relayClientService: RelayClientService
|
private val relayClientService: RelayClientService
|
||||||
) {
|
) {
|
||||||
@@ -1070,7 +1078,7 @@ class AccountService(
|
|||||||
/**
|
/**
|
||||||
* 从订单表获取最优价(用于市价单)
|
* 从订单表获取最优价(用于市价单)
|
||||||
* 支持多元市场(二元、三元及以上)
|
* 支持多元市场(二元、三元及以上)
|
||||||
* 委托给 PolymarketClobService.getOptimalPrice 方法
|
* 委托给 com.wrbug.polymarketbot.service.common.PolymarketClobService.getOptimalPrice 方法
|
||||||
*
|
*
|
||||||
* @param tokenId token ID(通过 marketId 和 outcomeIndex 计算得出)
|
* @param tokenId token ID(通过 marketId 和 outcomeIndex 计算得出)
|
||||||
* @param isSellOrder 是否为卖出订单(true: 卖单,需要 bestBid;false: 买单,需要 bestAsk)
|
* @param isSellOrder 是否为卖出订单(true: 卖单,需要 bestBid;false: 买单,需要 bestAsk)
|
||||||
@@ -1167,7 +1175,7 @@ class AccountService(
|
|||||||
/**
|
/**
|
||||||
* 获取可赎回仓位统计
|
* 获取可赎回仓位统计
|
||||||
*/
|
*/
|
||||||
suspend fun getRedeemablePositionsSummary(accountId: Long? = null): Result<com.wrbug.polymarketbot.dto.RedeemablePositionsSummary> {
|
suspend fun getRedeemablePositionsSummary(accountId: Long? = null): Result<RedeemablePositionsSummary> {
|
||||||
return try {
|
return try {
|
||||||
val positionsResult = getAllPositions()
|
val positionsResult = getAllPositions()
|
||||||
positionsResult.fold(
|
positionsResult.fold(
|
||||||
@@ -1223,7 +1231,7 @@ class AccountService(
|
|||||||
* 赎回仓位
|
* 赎回仓位
|
||||||
* 支持多账户、多仓位赎回(自动按账户和市场分组)
|
* 支持多账户、多仓位赎回(自动按账户和市场分组)
|
||||||
*/
|
*/
|
||||||
suspend fun redeemPositions(request: com.wrbug.polymarketbot.dto.PositionRedeemRequest): Result<com.wrbug.polymarketbot.dto.PositionRedeemResponse> {
|
suspend fun redeemPositions(request: PositionRedeemRequest): Result<PositionRedeemResponse> {
|
||||||
return try {
|
return try {
|
||||||
// 检查 Builder API Key 是否已配置
|
// 检查 Builder API Key 是否已配置
|
||||||
if (!relayClientService.isBuilderApiKeyConfigured()) {
|
if (!relayClientService.isBuilderApiKeyConfigured()) {
|
||||||
+7
-4
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.accounts
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
||||||
import com.wrbug.polymarketbot.entity.CopyOrderTracking
|
import com.wrbug.polymarketbot.entity.CopyOrderTracking
|
||||||
@@ -18,6 +18,9 @@ import jakarta.annotation.PostConstruct
|
|||||||
import jakarta.annotation.PreDestroy
|
import jakarta.annotation.PreDestroy
|
||||||
import org.springframework.context.MessageSource
|
import org.springframework.context.MessageSource
|
||||||
import org.springframework.context.i18n.LocaleContextHolder
|
import org.springframework.context.i18n.LocaleContextHolder
|
||||||
|
import com.wrbug.polymarketbot.service.system.SystemConfigService
|
||||||
|
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||||
|
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -368,15 +371,15 @@ class PositionCheckService(
|
|||||||
if (position == null) {
|
if (position == null) {
|
||||||
// 仓位不存在,更新所有订单状态为已卖出
|
// 仓位不存在,更新所有订单状态为已卖出
|
||||||
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
||||||
updateOrdersAsSold(orders, currentPrice, copyTrading.id!!, marketId, outcomeIndex)
|
updateOrdersAsSold(orders, currentPrice, copyTrading.id, marketId, outcomeIndex)
|
||||||
} else {
|
} else {
|
||||||
// 有仓位,按订单下单顺序(FIFO)更新状态
|
// 有仓位,按订单下单顺序(FIFO)更新状态
|
||||||
// 如果仓位数量 >= 订单数量总和,所有订单完全成交
|
// 如果仓位数量 >= 订单数量总和,所有订单完全成交
|
||||||
// 如果仓位数量 < 订单数量总和,按FIFO顺序部分成交
|
// 如果仓位数量 < 订单数量总和,按FIFO顺序部分成交
|
||||||
val totalUnmatchedQuantity = orders.sumOf { it.remainingQuantity.toSafeBigDecimal() }
|
|
||||||
val positionQuantity = position.quantity.toSafeBigDecimal()
|
val positionQuantity = position.quantity.toSafeBigDecimal()
|
||||||
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
||||||
updateOrdersAsSoldByFIFO(orders, positionQuantity, currentPrice, copyTrading.id!!, marketId, outcomeIndex)
|
updateOrdersAsSoldByFIFO(orders, positionQuantity, currentPrice,
|
||||||
|
copyTrading.id, marketId, outcomeIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.accounts
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.PositionListResponse
|
import com.wrbug.polymarketbot.dto.PositionListResponse
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.accounts
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
||||||
|
import com.wrbug.polymarketbot.dto.PositionListResponse
|
||||||
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
||||||
import com.wrbug.polymarketbot.dto.PositionPushMessageType
|
import com.wrbug.polymarketbot.dto.PositionPushMessageType
|
||||||
import com.wrbug.polymarketbot.dto.getPositionKey
|
import com.wrbug.polymarketbot.dto.getPositionKey
|
||||||
@@ -155,7 +156,7 @@ class PositionPushService(
|
|||||||
* 处理仓位更新事件
|
* 处理仓位更新事件
|
||||||
* 根据文档要求:每次轮训完成后向订阅者发送全量数据
|
* 根据文档要求:每次轮训完成后向订阅者发送全量数据
|
||||||
*/
|
*/
|
||||||
private fun handlePositionUpdate(positions: com.wrbug.polymarketbot.dto.PositionListResponse) {
|
private fun handlePositionUpdate(positions: PositionListResponse) {
|
||||||
// 更新快照
|
// 更新快照
|
||||||
lastCurrentPositions = positions.currentPositions.associateBy { it.getPositionKey() }
|
lastCurrentPositions = positions.currentPositions.associateBy { it.getPositionKey() }
|
||||||
lastHistoryPositions = positions.historyPositions.associateBy { it.getPositionKey() }
|
lastHistoryPositions = positions.historyPositions.associateBy { it.getPositionKey() }
|
||||||
+74
-75
@@ -1,6 +1,7 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.announcement
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.GitHubApi
|
import com.wrbug.polymarketbot.api.GitHubApi
|
||||||
|
import com.wrbug.polymarketbot.api.GitHubCommentResponse
|
||||||
import com.wrbug.polymarketbot.dto.AnnouncementDto
|
import com.wrbug.polymarketbot.dto.AnnouncementDto
|
||||||
import com.wrbug.polymarketbot.dto.AnnouncementListResponse
|
import com.wrbug.polymarketbot.dto.AnnouncementListResponse
|
||||||
import com.wrbug.polymarketbot.util.RetrofitFactory
|
import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||||
@@ -25,30 +26,30 @@ class AnnouncementService(
|
|||||||
@Value("\${github.announcement.issue.number:1}")
|
@Value("\${github.announcement.issue.number:1}")
|
||||||
private val issueNumber: Int
|
private val issueNumber: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(AnnouncementService::class.java)
|
private val logger = LoggerFactory.getLogger(AnnouncementService::class.java)
|
||||||
|
|
||||||
// GitHub API 客户端(懒加载)
|
// GitHub API 客户端(懒加载)
|
||||||
private val githubApi: GitHubApi by lazy {
|
private val githubApi: GitHubApi by lazy {
|
||||||
retrofitFactory.createGitHubApi()
|
retrofitFactory.createGitHubApi()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要排除的 Issue ID(从 issue_url 中提取)
|
// 需要排除的 Issue ID(从 issue_url 中提取)
|
||||||
private val excludedIssueId = "3703128976"
|
private val excludedIssueId = "3703128976"
|
||||||
|
|
||||||
// 缓存数据(1分钟有效期)
|
// 缓存数据(1分钟有效期)
|
||||||
private data class CachedData<T>(
|
private data class CachedData<T>(
|
||||||
val data: T,
|
val data: T,
|
||||||
val timestamp: Long
|
val timestamp: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
private var cachedList: CachedData<AnnouncementListResponse>? = null
|
private var cachedList: CachedData<AnnouncementListResponse>? = null
|
||||||
private var cachedAssignees: CachedData<List<String>>? = null
|
private var cachedAssignees: CachedData<List<String>>? = null
|
||||||
private var cachedComments: CachedData<List<com.wrbug.polymarketbot.api.GitHubCommentResponse>>? = null
|
private var cachedComments: CachedData<List<com.wrbug.polymarketbot.api.GitHubCommentResponse>>? = null
|
||||||
|
|
||||||
// 缓存有效期:10分钟(毫秒)
|
// 缓存有效期:10分钟(毫秒)
|
||||||
private val cacheExpiryTime = 10 * 60 * 1000L
|
private val cacheExpiryTime = 10 * 60 * 1000L
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查缓存是否有效
|
* 检查缓存是否有效
|
||||||
*/
|
*/
|
||||||
@@ -57,7 +58,7 @@ class AnnouncementService(
|
|||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
return (now - cached.timestamp) < cacheExpiryTime
|
return (now - cached.timestamp) < cacheExpiryTime
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否被限流
|
* 检查是否被限流
|
||||||
*/
|
*/
|
||||||
@@ -70,7 +71,7 @@ class AnnouncementService(
|
|||||||
val remaining = response.headers()["X-RateLimit-Remaining"]
|
val remaining = response.headers()["X-RateLimit-Remaining"]
|
||||||
return remaining == "0"
|
return remaining == "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Issue 的 assignees 列表(通过 API 获取,带缓存)
|
* 获取 Issue 的 assignees 列表(通过 API 获取,带缓存)
|
||||||
* @return Pair<assignees列表, 是否使用了缓存>
|
* @return Pair<assignees列表, 是否使用了缓存>
|
||||||
@@ -81,14 +82,14 @@ class AnnouncementService(
|
|||||||
logger.debug("使用缓存的 assignees")
|
logger.debug("使用缓存的 assignees")
|
||||||
return Pair(cachedAssignees!!.data, true)
|
return Pair(cachedAssignees!!.data, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
val response = githubApi.getIssue(
|
val response = githubApi.getIssue(
|
||||||
owner = repoOwner,
|
owner = repoOwner,
|
||||||
repo = repoName,
|
repo = repoName,
|
||||||
issueNumber = issueNumber
|
issueNumber = issueNumber
|
||||||
)
|
)
|
||||||
|
|
||||||
// 如果被限流,使用缓存数据,不更新缓存
|
// 如果被限流,使用缓存数据,不更新缓存
|
||||||
if (isRateLimited(response)) {
|
if (isRateLimited(response)) {
|
||||||
logger.warn("GitHub API 被限流,使用缓存的 assignees(不更新缓存)")
|
logger.warn("GitHub API 被限流,使用缓存的 assignees(不更新缓存)")
|
||||||
@@ -98,14 +99,14 @@ class AnnouncementService(
|
|||||||
// 如果没有缓存,使用默认值
|
// 如果没有缓存,使用默认值
|
||||||
return Pair(listOf("WrBug"), false)
|
return Pair(listOf("WrBug"), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
val assignees = if (response.isSuccessful && response.body() != null) {
|
val assignees = if (response.isSuccessful && response.body() != null) {
|
||||||
response.body()!!.assignees.map { it.login }
|
response.body()!!.assignees.map { it.login }
|
||||||
} else {
|
} else {
|
||||||
logger.warn("获取 Issue assignees 失败,使用默认值: code=${response.code()}")
|
logger.warn("获取 Issue assignees 失败,使用默认值: code=${response.code()}")
|
||||||
listOf("WrBug") // 默认值
|
listOf("WrBug") // 默认值
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新缓存
|
// 更新缓存
|
||||||
cachedAssignees = CachedData(assignees, System.currentTimeMillis())
|
cachedAssignees = CachedData(assignees, System.currentTimeMillis())
|
||||||
Pair(assignees, false) // 返回新数据,标记为未使用缓存
|
Pair(assignees, false) // 返回新数据,标记为未使用缓存
|
||||||
@@ -119,24 +120,24 @@ class AnnouncementService(
|
|||||||
Pair(listOf("WrBug"), false) // 默认值
|
Pair(listOf("WrBug"), false) // 默认值
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Issue 评论列表(带缓存)
|
* 获取 Issue 评论列表(带缓存)
|
||||||
* @return Pair<评论列表, 是否使用了缓存>
|
* @return Pair<评论列表, 是否使用了缓存>
|
||||||
*/
|
*/
|
||||||
private suspend fun getIssueComments(forceRefresh: Boolean = false): Pair<List<com.wrbug.polymarketbot.api.GitHubCommentResponse>, Boolean> {
|
private suspend fun getIssueComments(forceRefresh: Boolean = false): Pair<List<GitHubCommentResponse>, Boolean> {
|
||||||
// 检查缓存
|
// 检查缓存
|
||||||
if (!forceRefresh && isCacheValid(cachedComments)) {
|
if (!forceRefresh && isCacheValid(cachedComments)) {
|
||||||
logger.debug("使用缓存的评论列表")
|
logger.debug("使用缓存的评论列表")
|
||||||
return Pair(cachedComments!!.data, true)
|
return Pair(cachedComments!!.data, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val response = githubApi.getIssueComments(
|
val response = githubApi.getIssueComments(
|
||||||
owner = repoOwner,
|
owner = repoOwner,
|
||||||
repo = repoName,
|
repo = repoName,
|
||||||
issueNumber = issueNumber
|
issueNumber = issueNumber
|
||||||
)
|
)
|
||||||
|
|
||||||
// 如果被限流,使用缓存数据,不更新缓存
|
// 如果被限流,使用缓存数据,不更新缓存
|
||||||
if (isRateLimited(response)) {
|
if (isRateLimited(response)) {
|
||||||
logger.warn("GitHub API 被限流,使用缓存的评论列表(不更新缓存)")
|
logger.warn("GitHub API 被限流,使用缓存的评论列表(不更新缓存)")
|
||||||
@@ -146,7 +147,7 @@ class AnnouncementService(
|
|||||||
// 如果没有缓存,抛出异常
|
// 如果没有缓存,抛出异常
|
||||||
throw Exception("获取公告列表失败: GitHub API 被限流,且无缓存数据")
|
throw Exception("获取公告列表失败: GitHub API 被限流,且无缓存数据")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.isSuccessful || response.body() == null) {
|
if (!response.isSuccessful || response.body() == null) {
|
||||||
logger.error("获取 GitHub Issue 评论失败: code=${response.code()}, message=${response.message()}")
|
logger.error("获取 GitHub Issue 评论失败: code=${response.code()}, message=${response.message()}")
|
||||||
// 如果缓存存在,使用缓存
|
// 如果缓存存在,使用缓存
|
||||||
@@ -156,14 +157,14 @@ class AnnouncementService(
|
|||||||
}
|
}
|
||||||
throw Exception("获取公告列表失败: HTTP ${response.code()}")
|
throw Exception("获取公告列表失败: HTTP ${response.code()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val comments = response.body()!!
|
val comments = response.body()!!
|
||||||
|
|
||||||
// 更新缓存
|
// 更新缓存
|
||||||
cachedComments = CachedData(comments, System.currentTimeMillis())
|
cachedComments = CachedData(comments, System.currentTimeMillis())
|
||||||
return Pair(comments, false) // 返回新数据,标记为未使用缓存
|
return Pair(comments, false) // 返回新数据,标记为未使用缓存
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取公告列表(最近10条)
|
* 获取公告列表(最近10条)
|
||||||
* @param forceRefresh 是否强制刷新缓存
|
* @param forceRefresh 是否强制刷新缓存
|
||||||
@@ -174,12 +175,12 @@ class AnnouncementService(
|
|||||||
logger.debug("使用缓存的公告列表")
|
logger.debug("使用缓存的公告列表")
|
||||||
return Result.success(cachedList!!.data)
|
return Result.success(cachedList!!.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
// 强制刷新时,先尝试获取新数据
|
// 强制刷新时,先尝试获取新数据
|
||||||
val (assigneeList, assigneesFromCache) = getAssignees(forceRefresh)
|
val (assigneeList, assigneesFromCache) = getAssignees(forceRefresh)
|
||||||
val (comments, commentsFromCache) = getIssueComments(forceRefresh)
|
val (comments, commentsFromCache) = getIssueComments(forceRefresh)
|
||||||
|
|
||||||
// 如果强制刷新时使用了缓存(被限流),直接返回缓存数据,不更新缓存
|
// 如果强制刷新时使用了缓存(被限流),直接返回缓存数据,不更新缓存
|
||||||
if (forceRefresh && (assigneesFromCache || commentsFromCache)) {
|
if (forceRefresh && (assigneesFromCache || commentsFromCache)) {
|
||||||
logger.warn("强制刷新时被限流,返回缓存的公告列表(不更新缓存)")
|
logger.warn("强制刷新时被限流,返回缓存的公告列表(不更新缓存)")
|
||||||
@@ -187,48 +188,47 @@ class AnnouncementService(
|
|||||||
return Result.success(cachedList!!.data)
|
return Result.success(cachedList!!.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 筛选条件:
|
// 筛选条件:
|
||||||
// 1. assignees 发布的评论
|
// 1. assignees 发布的评论
|
||||||
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
||||||
val filteredComments = comments
|
val filteredComments = comments.filter { comment ->
|
||||||
.filter { comment ->
|
// 检查是否为 assignee
|
||||||
// 检查是否为 assignee
|
val isAssignee = assigneeList.contains(comment.user.login)
|
||||||
val isAssignee = assigneeList.contains(comment.user.login)
|
|
||||||
|
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
||||||
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
||||||
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
||||||
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
// 提取最后的数字
|
||||||
// 提取最后的数字
|
val issueId = issueUrl.split("/").lastOrNull()
|
||||||
val issueId = issueUrl.split("/").lastOrNull()
|
issueId == excludedIssueId
|
||||||
issueId == excludedIssueId
|
} ?: false
|
||||||
} ?: false
|
|
||||||
|
isAssignee && !shouldExclude
|
||||||
isAssignee && !shouldExclude
|
}
|
||||||
}
|
|
||||||
.sortedByDescending { comment ->
|
.sortedByDescending { comment ->
|
||||||
parseGitHubTime(comment.created_at)
|
parseGitHubTime(comment.created_at)
|
||||||
}
|
}
|
||||||
|
|
||||||
val total = filteredComments.size
|
val total = filteredComments.size
|
||||||
val hasMore = total > 10
|
val hasMore = total > 10
|
||||||
|
|
||||||
// 取前10条
|
// 取前10条
|
||||||
val latest10 = filteredComments.take(10).map { comment ->
|
val latest10 = filteredComments.take(10).map { comment ->
|
||||||
toAnnouncementDto(comment)
|
toAnnouncementDto(comment)
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = AnnouncementListResponse(
|
val result = AnnouncementListResponse(
|
||||||
list = latest10,
|
list = latest10,
|
||||||
hasMore = hasMore,
|
hasMore = hasMore,
|
||||||
total = total
|
total = total
|
||||||
)
|
)
|
||||||
|
|
||||||
// 只有在数据正常返回时才更新缓存(不是从缓存获取的)
|
// 只有在数据正常返回时才更新缓存(不是从缓存获取的)
|
||||||
if (!assigneesFromCache && !commentsFromCache) {
|
if (!assigneesFromCache && !commentsFromCache) {
|
||||||
cachedList = CachedData(result, System.currentTimeMillis())
|
cachedList = CachedData(result, System.currentTimeMillis())
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.success(result)
|
Result.success(result)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("获取公告列表异常: ${e.message}", e)
|
logger.error("获取公告列表异常: ${e.message}", e)
|
||||||
@@ -240,7 +240,7 @@ class AnnouncementService(
|
|||||||
Result.failure(e)
|
Result.failure(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取公告详情
|
* 获取公告详情
|
||||||
* @param id 评论ID,如果为 null 则返回最新一条
|
* @param id 评论ID,如果为 null 则返回最新一条
|
||||||
@@ -249,19 +249,18 @@ class AnnouncementService(
|
|||||||
suspend fun getAnnouncementDetail(id: Long?, forceRefresh: Boolean = false): Result<AnnouncementDto> {
|
suspend fun getAnnouncementDetail(id: Long?, forceRefresh: Boolean = false): Result<AnnouncementDto> {
|
||||||
return try {
|
return try {
|
||||||
// 获取 assignees
|
// 获取 assignees
|
||||||
val (assigneeList, assigneesFromCache) = getAssignees(forceRefresh)
|
val (assigneeList, _) = getAssignees(forceRefresh)
|
||||||
|
|
||||||
// 获取评论列表
|
// 获取评论列表
|
||||||
val (comments, commentsFromCache) = getIssueComments(forceRefresh)
|
val (comments, _) = getIssueComments(forceRefresh)
|
||||||
|
|
||||||
// 筛选条件:
|
// 筛选条件:
|
||||||
// 1. assignees 发布的评论
|
// 1. assignees 发布的评论
|
||||||
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
||||||
val filteredComments = comments
|
val filteredComments = comments.filter { comment ->
|
||||||
.filter { comment ->
|
|
||||||
// 检查是否为 assignee
|
// 检查是否为 assignee
|
||||||
val isAssignee = assigneeList.contains(comment.user.login)
|
val isAssignee = assigneeList.contains(comment.user.login)
|
||||||
|
|
||||||
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
||||||
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
||||||
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
||||||
@@ -269,37 +268,37 @@ class AnnouncementService(
|
|||||||
val issueId = issueUrl.split("/").lastOrNull()
|
val issueId = issueUrl.split("/").lastOrNull()
|
||||||
issueId == excludedIssueId
|
issueId == excludedIssueId
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
isAssignee && !shouldExclude
|
isAssignee && !shouldExclude
|
||||||
}
|
}
|
||||||
.sortedByDescending { comment ->
|
.sortedByDescending { comment ->
|
||||||
parseGitHubTime(comment.created_at)
|
parseGitHubTime(comment.created_at)
|
||||||
}
|
}
|
||||||
|
|
||||||
val targetComment = if (id != null) {
|
val targetComment = if (id != null) {
|
||||||
filteredComments.find { it.id == id }
|
filteredComments.find { it.id == id }
|
||||||
} else {
|
} else {
|
||||||
filteredComments.firstOrNull()
|
filteredComments.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetComment == null) {
|
if (targetComment == null) {
|
||||||
return Result.failure(IllegalArgumentException("公告不存在"))
|
return Result.failure(IllegalArgumentException("公告不存在"))
|
||||||
}
|
}
|
||||||
|
|
||||||
Result.success(toAnnouncementDto(targetComment))
|
Result.success(toAnnouncementDto(targetComment))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("获取公告详情异常: ${e.message}", e)
|
logger.error("获取公告详情异常: ${e.message}", e)
|
||||||
Result.failure(e)
|
Result.failure(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 GitHub 评论转换为 AnnouncementDto
|
* 将 GitHub 评论转换为 AnnouncementDto
|
||||||
*/
|
*/
|
||||||
private fun toAnnouncementDto(comment: com.wrbug.polymarketbot.api.GitHubCommentResponse): AnnouncementDto {
|
private fun toAnnouncementDto(comment: GitHubCommentResponse): AnnouncementDto {
|
||||||
// 提取标题(第一行,移除 Markdown 格式)
|
// 提取标题(第一行,移除 Markdown 格式)
|
||||||
val title = extractTitle(comment.body)
|
val title = extractTitle(comment.body)
|
||||||
|
|
||||||
// 转换 reactions 数据
|
// 转换 reactions 数据
|
||||||
val reactions = comment.reactions?.let { r ->
|
val reactions = comment.reactions?.let { r ->
|
||||||
com.wrbug.polymarketbot.dto.ReactionsDto(
|
com.wrbug.polymarketbot.dto.ReactionsDto(
|
||||||
@@ -314,7 +313,7 @@ class AnnouncementService(
|
|||||||
total = r.total_count
|
total = r.total_count
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnnouncementDto(
|
return AnnouncementDto(
|
||||||
id = comment.id,
|
id = comment.id,
|
||||||
title = title,
|
title = title,
|
||||||
@@ -326,7 +325,7 @@ class AnnouncementService(
|
|||||||
reactions = reactions
|
reactions = reactions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从评论内容中提取标题(第一行,移除 Markdown 格式)
|
* 从评论内容中提取标题(第一行,移除 Markdown 格式)
|
||||||
* 支持的 Markdown 格式:
|
* 支持的 Markdown 格式:
|
||||||
@@ -342,49 +341,49 @@ class AnnouncementService(
|
|||||||
if (body.isBlank()) {
|
if (body.isBlank()) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取第一行
|
// 获取第一行
|
||||||
val firstLine = body.lines().firstOrNull()?.trim() ?: ""
|
val firstLine = body.lines().firstOrNull()?.trim() ?: ""
|
||||||
if (firstLine.isBlank()) {
|
if (firstLine.isBlank()) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除 Markdown 格式
|
// 移除 Markdown 格式
|
||||||
var title = firstLine
|
var title = firstLine
|
||||||
|
|
||||||
// 移除标题标记(# ## ### 等)
|
// 移除标题标记(# ## ### 等)
|
||||||
title = title.replace(Regex("^#{1,6}\\s+"), "")
|
title = title.replace(Regex("^#{1,6}\\s+"), "")
|
||||||
|
|
||||||
// 移除粗体标记(**text** 或 __text__)
|
// 移除粗体标记(**text** 或 __text__)
|
||||||
title = title.replace(Regex("\\*\\*([^*]+)\\*\\*"), "$1")
|
title = title.replace(Regex("\\*\\*([^*]+)\\*\\*"), "$1")
|
||||||
title = title.replace(Regex("__([^_]+)__"), "$1")
|
title = title.replace(Regex("__([^_]+)__"), "$1")
|
||||||
|
|
||||||
// 移除斜体标记(*text* 或 _text_)
|
// 移除斜体标记(*text* 或 _text_)
|
||||||
title = title.replace(Regex("(?<!\\*)\\*([^*]+)\\*(?!\\*)"), "$1")
|
title = title.replace(Regex("(?<!\\*)\\*([^*]+)\\*(?!\\*)"), "$1")
|
||||||
title = title.replace(Regex("(?<!_)_([^_]+)_(?!_)"), "$1")
|
title = title.replace(Regex("(?<!_)_([^_]+)_(?!_)"), "$1")
|
||||||
|
|
||||||
// 移除代码标记(`code`)
|
// 移除代码标记(`code`)
|
||||||
title = title.replace(Regex("`([^`]+)`"), "$1")
|
title = title.replace(Regex("`([^`]+)`"), "$1")
|
||||||
|
|
||||||
// 移除链接标记([text](url))
|
// 移除链接标记([text](url))
|
||||||
title = title.replace(Regex("\\[([^\\]]+)\\]\\([^\\)]+\\)"), "$1")
|
title = title.replace(Regex("\\[([^\\]]+)\\]\\([^\\)]+\\)"), "$1")
|
||||||
|
|
||||||
// 移除图片标记()
|
// 移除图片标记()
|
||||||
title = title.replace(Regex("!\\[([^\\]]*)\\]\\([^\\)]+\\)"), "$1")
|
title = title.replace(Regex("!\\[([^\\]]*)\\]\\([^\\)]+\\)"), "$1")
|
||||||
|
|
||||||
// 移除删除线标记(~~text~~)
|
// 移除删除线标记(~~text~~)
|
||||||
title = title.replace(Regex("~~([^~]+)~~"), "$1")
|
title = title.replace(Regex("~~([^~]+)~~"), "$1")
|
||||||
|
|
||||||
// 移除引用标记(> text)
|
// 移除引用标记(> text)
|
||||||
title = title.replace(Regex("^>\\s+"), "")
|
title = title.replace(Regex("^>\\s+"), "")
|
||||||
|
|
||||||
// 移除列表标记(- * + 1. 等)
|
// 移除列表标记(- * + 1. 等)
|
||||||
title = title.replace(Regex("^[-*+]\\s+"), "")
|
title = title.replace(Regex("^[-*+]\\s+"), "")
|
||||||
title = title.replace(Regex("^\\d+\\.\\s+"), "")
|
title = title.replace(Regex("^\\d+\\.\\s+"), "")
|
||||||
|
|
||||||
return title.trim()
|
return title.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 GitHub 时间格式(ISO 8601)为时间戳(毫秒)
|
* 解析 GitHub 时间格式(ISO 8601)为时间戳(毫秒)
|
||||||
* GitHub API 返回的时间格式:2025-12-07T14:30:00Z
|
* GitHub API 返回的时间格式:2025-12-07T14:30:00Z
|
||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.auth
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.CheckFirstUseResponse
|
import com.wrbug.polymarketbot.dto.CheckFirstUseResponse
|
||||||
import com.wrbug.polymarketbot.dto.LoginResponse
|
import com.wrbug.polymarketbot.dto.LoginResponse
|
||||||
@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletRequest
|
|||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
|
import com.wrbug.polymarketbot.service.common.RateLimitService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
|
||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.common
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
||||||
import com.wrbug.polymarketbot.api.JsonRpcRequest
|
import com.wrbug.polymarketbot.api.JsonRpcRequest
|
||||||
@@ -11,6 +11,7 @@ import com.wrbug.polymarketbot.util.RetrofitFactory
|
|||||||
import com.wrbug.polymarketbot.util.createClient
|
import com.wrbug.polymarketbot.util.createClient
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.common
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.ApiKeyResponse
|
import com.wrbug.polymarketbot.api.ApiKeyResponse
|
||||||
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.common
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.*
|
import com.wrbug.polymarketbot.api.*
|
||||||
import com.wrbug.polymarketbot.util.RetrofitFactory
|
import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.common
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
+3
-1
@@ -1,9 +1,11 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.common
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
||||||
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
||||||
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
||||||
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
||||||
|
import com.wrbug.polymarketbot.service.accounts.PositionPushService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
+2
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.OrderbookResponse
|
import com.wrbug.polymarketbot.api.OrderbookResponse
|
||||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||||
@@ -7,6 +7,7 @@ import com.wrbug.polymarketbot.util.lt
|
|||||||
import com.wrbug.polymarketbot.util.multi
|
import com.wrbug.polymarketbot.util.multi
|
||||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
|
|
||||||
+7
-4
@@ -1,11 +1,14 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
|
import com.wrbug.polymarketbot.entity.Account
|
||||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||||
|
import com.wrbug.polymarketbot.entity.Leader
|
||||||
import com.wrbug.polymarketbot.repository.AccountRepository
|
import com.wrbug.polymarketbot.repository.AccountRepository
|
||||||
import com.wrbug.polymarketbot.repository.CopyTradingRepository
|
import com.wrbug.polymarketbot.repository.CopyTradingRepository
|
||||||
import com.wrbug.polymarketbot.repository.CopyTradingTemplateRepository
|
import com.wrbug.polymarketbot.repository.CopyTradingTemplateRepository
|
||||||
import com.wrbug.polymarketbot.repository.LeaderRepository
|
import com.wrbug.polymarketbot.repository.LeaderRepository
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingMonitorService
|
||||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
@@ -339,7 +342,7 @@ class CopyTradingService(
|
|||||||
fun getAccountTemplates(accountId: Long): Result<AccountTemplatesResponse> {
|
fun getAccountTemplates(accountId: Long): Result<AccountTemplatesResponse> {
|
||||||
return try {
|
return try {
|
||||||
// 验证账户是否存在
|
// 验证账户是否存在
|
||||||
val account = accountRepository.findById(accountId).orElse(null)
|
accountRepository.findById(accountId).orElse(null)
|
||||||
?: return Result.failure(IllegalArgumentException("账户不存在"))
|
?: return Result.failure(IllegalArgumentException("账户不存在"))
|
||||||
|
|
||||||
val copyTradings = copyTradingRepository.findByAccountId(accountId)
|
val copyTradings = copyTradingRepository.findByAccountId(accountId)
|
||||||
@@ -380,8 +383,8 @@ class CopyTradingService(
|
|||||||
*/
|
*/
|
||||||
private fun toDto(
|
private fun toDto(
|
||||||
copyTrading: CopyTrading,
|
copyTrading: CopyTrading,
|
||||||
account: com.wrbug.polymarketbot.entity.Account,
|
account: Account,
|
||||||
leader: com.wrbug.polymarketbot.entity.Leader
|
leader: Leader
|
||||||
): CopyTradingDto {
|
): CopyTradingDto {
|
||||||
return CopyTradingDto(
|
return CopyTradingDto(
|
||||||
id = copyTrading.id!!,
|
id = copyTrading.id!!,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.FilteredOrderDto
|
import com.wrbug.polymarketbot.dto.FilteredOrderDto
|
||||||
import com.wrbug.polymarketbot.dto.FilteredOrderListRequest
|
import com.wrbug.polymarketbot.dto.FilteredOrderListRequest
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.leaders
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.entity.Leader
|
import com.wrbug.polymarketbot.entity.Leader
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||||
import com.wrbug.polymarketbot.entity.Leader
|
import com.wrbug.polymarketbot.entity.Leader
|
||||||
+4
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.TradeResponse
|
import com.wrbug.polymarketbot.api.TradeResponse
|
||||||
import com.wrbug.polymarketbot.api.UserActivityResponse
|
import com.wrbug.polymarketbot.api.UserActivityResponse
|
||||||
@@ -9,6 +9,7 @@ import jakarta.annotation.PreDestroy
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyOrderTrackingService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
@@ -72,7 +73,7 @@ class CopyTradingPollingService(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val leaderId = leader.id!!
|
val leaderId = leader.id
|
||||||
monitoredLeaders[leaderId] = leader
|
monitoredLeaders[leaderId] = leader
|
||||||
// 初始化缓存的交易ID集合
|
// 初始化缓存的交易ID集合
|
||||||
cachedTradeIds[leaderId] = mutableSetOf()
|
cachedTradeIds[leaderId] = mutableSetOf()
|
||||||
@@ -178,7 +179,7 @@ class CopyTradingPollingService(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val leaderId = leader.id!!
|
val leaderId = leader.id
|
||||||
val leaderAddress = leader.leaderAddress
|
val leaderAddress = leader.leaderAddress
|
||||||
|
|
||||||
try {
|
try {
|
||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
@@ -11,6 +11,7 @@ import jakarta.annotation.PreDestroy
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyOrderTrackingService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ class CopyTradingWebSocketService(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val leaderId = leader.id!!
|
val leaderId = leader.id
|
||||||
val leaderAddress = leader.leaderAddress.lowercase()
|
val leaderAddress = leader.leaderAddress.lowercase()
|
||||||
leaderAddresses[leaderId] = leaderAddress
|
leaderAddresses[leaderId] = leaderAddress
|
||||||
|
|
||||||
+17
-11
@@ -1,6 +1,7 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.orders
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.wrbug.polymarketbot.api.MarketResponse
|
||||||
import com.wrbug.polymarketbot.dto.OrderDetailDto
|
import com.wrbug.polymarketbot.dto.OrderDetailDto
|
||||||
import com.wrbug.polymarketbot.dto.OrderMessageDto
|
import com.wrbug.polymarketbot.dto.OrderMessageDto
|
||||||
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
||||||
@@ -13,6 +14,11 @@ import jakarta.annotation.PreDestroy
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||||
|
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||||
|
import com.wrbug.polymarketbot.repository.CopyOrderTrackingRepository
|
||||||
|
import com.wrbug.polymarketbot.repository.CopyTradingRepository
|
||||||
|
import com.wrbug.polymarketbot.repository.LeaderRepository
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
@@ -26,10 +32,10 @@ class OrderPushService(
|
|||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val clobService: PolymarketClobService,
|
private val clobService: PolymarketClobService,
|
||||||
private val retrofitFactory: RetrofitFactory, // 用于创建 Gamma API 客户端(不需要认证)
|
private val retrofitFactory: RetrofitFactory, // 用于创建 Gamma API 客户端(不需要认证)
|
||||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
private val cryptoUtils: CryptoUtils,
|
||||||
private val copyOrderTrackingRepository: com.wrbug.polymarketbot.repository.CopyOrderTrackingRepository? = null, // 可选,避免循环依赖
|
private val copyOrderTrackingRepository: CopyOrderTrackingRepository? = null, // 可选,避免循环依赖
|
||||||
private val copyTradingRepository: com.wrbug.polymarketbot.repository.CopyTradingRepository? = null, // 可选,避免循环依赖
|
private val copyTradingRepository: CopyTradingRepository? = null, // 可选,避免循环依赖
|
||||||
private val leaderRepository: com.wrbug.polymarketbot.repository.LeaderRepository? = null // 可选,避免循环依赖
|
private val leaderRepository: LeaderRepository? = null // 可选,避免循环依赖
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(OrderPushService::class.java)
|
private val logger = LoggerFactory.getLogger(OrderPushService::class.java)
|
||||||
@@ -152,9 +158,9 @@ class OrderPushService(
|
|||||||
return account.apiKey != null &&
|
return account.apiKey != null &&
|
||||||
account.apiSecret != null &&
|
account.apiSecret != null &&
|
||||||
account.apiPassphrase != null &&
|
account.apiPassphrase != null &&
|
||||||
account.apiKey!!.isNotBlank() &&
|
account.apiKey.isNotBlank() &&
|
||||||
account.apiSecret!!.isNotBlank() &&
|
account.apiSecret.isNotBlank() &&
|
||||||
account.apiPassphrase!!.isNotBlank()
|
account.apiPassphrase.isNotBlank()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -378,7 +384,7 @@ class OrderPushService(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取订单详情
|
* 获取订单详情
|
||||||
* 通过 PolymarketClobService 获取订单详情
|
* 通过 com.wrbug.polymarketbot.service.common.PolymarketClobService 获取订单详情
|
||||||
*/
|
*/
|
||||||
private suspend fun fetchOrderDetail(
|
private suspend fun fetchOrderDetail(
|
||||||
account: Account,
|
account: Account,
|
||||||
@@ -391,7 +397,7 @@ class OrderPushService(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过 PolymarketClobService 获取订单详情(需要 L2 认证)
|
// 通过 com.wrbug.polymarketbot.service.common.PolymarketClobService 获取订单详情(需要 L2 认证)
|
||||||
// 解密 API 凭证
|
// 解密 API 凭证
|
||||||
val apiSecret = try {
|
val apiSecret = try {
|
||||||
decryptApiSecret(account)
|
decryptApiSecret(account)
|
||||||
@@ -453,7 +459,7 @@ class OrderPushService(
|
|||||||
* 使用 /markets 接口,通过 condition_ids 查询参数获取市场信息
|
* 使用 /markets 接口,通过 condition_ids 查询参数获取市场信息
|
||||||
* 订单返回的 market 字段是 16 进制的 condition ID(如 "0x...")
|
* 订单返回的 market 字段是 16 进制的 condition ID(如 "0x...")
|
||||||
*/
|
*/
|
||||||
private suspend fun fetchMarketInfo(conditionId: String): com.wrbug.polymarketbot.api.MarketResponse? {
|
private suspend fun fetchMarketInfo(conditionId: String): MarketResponse? {
|
||||||
return try {
|
return try {
|
||||||
// 创建 Gamma API 客户端(公开 API,不需要认证)
|
// 创建 Gamma API 客户端(公开 API,不需要认证)
|
||||||
val gammaApi = retrofitFactory.createGammaApi()
|
val gammaApi = retrofitFactory.createGammaApi()
|
||||||
+1
-5
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.orders
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.SignedOrderObject
|
import com.wrbug.polymarketbot.api.SignedOrderObject
|
||||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||||
@@ -77,10 +77,6 @@ class OrderSigningService {
|
|||||||
): OrderAmounts {
|
): OrderAmounts {
|
||||||
val sizeDecimal = size.toSafeBigDecimal()
|
val sizeDecimal = size.toSafeBigDecimal()
|
||||||
val priceDecimal = price.toSafeBigDecimal()
|
val priceDecimal = price.toSafeBigDecimal()
|
||||||
|
|
||||||
// 舍入价格
|
|
||||||
val roundedPrice = roundNormal(priceDecimal, roundConfig.price)
|
|
||||||
|
|
||||||
if (side.uppercase() == "BUY") {
|
if (side.uppercase() == "BUY") {
|
||||||
// BUY: makerAmount = price * size (USDC), takerAmount = size (shares)
|
// BUY: makerAmount = price * size (USDC), takerAmount = size (shares)
|
||||||
// makerAmount 是 USDC 金额,最多 2 位小数
|
// makerAmount 是 USDC 金额,最多 2 位小数
|
||||||
+19
-13
@@ -1,6 +1,7 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.statistics
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.NewOrderRequest
|
import com.wrbug.polymarketbot.api.NewOrderRequest
|
||||||
|
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||||
import com.wrbug.polymarketbot.api.TradeResponse
|
import com.wrbug.polymarketbot.api.TradeResponse
|
||||||
import com.wrbug.polymarketbot.entity.*
|
import com.wrbug.polymarketbot.entity.*
|
||||||
import com.wrbug.polymarketbot.repository.*
|
import com.wrbug.polymarketbot.repository.*
|
||||||
@@ -9,6 +10,11 @@ import com.wrbug.polymarketbot.util.*
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.dao.DataIntegrityViolationException
|
import org.springframework.dao.DataIntegrityViolationException
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.configs.CopyTradingFilterService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderSigningService
|
||||||
|
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||||
|
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||||
|
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
@@ -33,7 +39,7 @@ class CopyOrderTrackingService(
|
|||||||
private val orderSigningService: OrderSigningService,
|
private val orderSigningService: OrderSigningService,
|
||||||
private val blockchainService: BlockchainService,
|
private val blockchainService: BlockchainService,
|
||||||
private val retrofitFactory: RetrofitFactory,
|
private val retrofitFactory: RetrofitFactory,
|
||||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
private val cryptoUtils: CryptoUtils,
|
||||||
private val telegramNotificationService: TelegramNotificationService? = null // 可选,避免循环依赖
|
private val telegramNotificationService: TelegramNotificationService? = null // 可选,避免循环依赖
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -381,7 +387,7 @@ class CopyOrderTrackingService(
|
|||||||
side = "BUY",
|
side = "BUY",
|
||||||
price = buyPrice.toString(),
|
price = buyPrice.toString(),
|
||||||
size = finalBuyQuantity.toString(),
|
size = finalBuyQuantity.toString(),
|
||||||
owner = account.apiKey!!,
|
owner = account.apiKey,
|
||||||
copyTradingId = copyTrading.id!!,
|
copyTradingId = copyTrading.id!!,
|
||||||
tradeId = trade.id
|
tradeId = trade.id
|
||||||
)
|
)
|
||||||
@@ -759,7 +765,7 @@ class CopyOrderTrackingService(
|
|||||||
// 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配
|
// 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配
|
||||||
val orderRequest = NewOrderRequest(
|
val orderRequest = NewOrderRequest(
|
||||||
order = signedOrder,
|
order = signedOrder,
|
||||||
owner = account.apiKey!!,
|
owner = account.apiKey,
|
||||||
orderType = "FAK", // Fill-And-Kill
|
orderType = "FAK", // Fill-And-Kill
|
||||||
deferExec = false
|
deferExec = false
|
||||||
)
|
)
|
||||||
@@ -782,8 +788,8 @@ class CopyOrderTrackingService(
|
|||||||
side = "SELL",
|
side = "SELL",
|
||||||
price = sellPrice.toString(),
|
price = sellPrice.toString(),
|
||||||
size = totalMatched.toString(),
|
size = totalMatched.toString(),
|
||||||
owner = account.apiKey!!,
|
owner = account.apiKey,
|
||||||
copyTradingId = copyTrading.id!!,
|
copyTradingId = copyTrading.id,
|
||||||
tradeId = leaderSellTrade.id
|
tradeId = leaderSellTrade.id
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -830,11 +836,11 @@ class CopyOrderTrackingService(
|
|||||||
val totalRealizedPnl = matchDetails.sumOf { it.realizedPnl.toSafeBigDecimal() }
|
val totalRealizedPnl = matchDetails.sumOf { it.realizedPnl.toSafeBigDecimal() }
|
||||||
|
|
||||||
val matchRecord = SellMatchRecord(
|
val matchRecord = SellMatchRecord(
|
||||||
copyTradingId = copyTrading.id!!,
|
copyTradingId = copyTrading.id,
|
||||||
sellOrderId = realSellOrderId, // 使用真实订单ID
|
sellOrderId = realSellOrderId, // 使用真实订单ID
|
||||||
leaderSellTradeId = leaderSellTrade.id,
|
leaderSellTradeId = leaderSellTrade.id,
|
||||||
marketId = leaderSellTrade.market,
|
marketId = leaderSellTrade.market,
|
||||||
side = leaderSellTrade.outcomeIndex?.toString() ?: "0", // 使用outcomeIndex作为side(兼容旧数据)
|
side = leaderSellTrade.outcomeIndex.toString(), // 使用outcomeIndex作为side(兼容旧数据)
|
||||||
outcomeIndex = leaderSellTrade.outcomeIndex, // 新增字段
|
outcomeIndex = leaderSellTrade.outcomeIndex, // 新增字段
|
||||||
totalMatchedQuantity = totalMatched,
|
totalMatchedQuantity = totalMatched,
|
||||||
sellPrice = sellPrice,
|
sellPrice = sellPrice,
|
||||||
@@ -857,7 +863,7 @@ class CopyOrderTrackingService(
|
|||||||
* 注意:重试时会重新生成salt并重新签名,确保每次重试都是新的订单
|
* 注意:重试时会重新生成salt并重新签名,确保每次重试都是新的订单
|
||||||
*/
|
*/
|
||||||
private suspend fun createOrderWithRetry(
|
private suspend fun createOrderWithRetry(
|
||||||
clobApi: com.wrbug.polymarketbot.api.PolymarketClobApi,
|
clobApi: PolymarketClobApi,
|
||||||
privateKey: String,
|
privateKey: String,
|
||||||
makerAddress: String,
|
makerAddress: String,
|
||||||
tokenId: String,
|
tokenId: String,
|
||||||
@@ -914,7 +920,7 @@ class CopyOrderTrackingService(
|
|||||||
delay(1000) // 重试前等待1秒
|
delay(1000) // 重试前等待1秒
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return Result.failure(lastError!!)
|
return Result.failure(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
val response = orderResponse.body()!!
|
val response = orderResponse.body()!!
|
||||||
@@ -928,7 +934,7 @@ class CopyOrderTrackingService(
|
|||||||
delay(1000) // 重试前等待1秒
|
delay(1000) // 重试前等待1秒
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return Result.failure(lastError!!)
|
return Result.failure(lastError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 成功
|
// 成功
|
||||||
@@ -943,7 +949,7 @@ class CopyOrderTrackingService(
|
|||||||
delay(1000) // 重试前等待1秒
|
delay(1000) // 重试前等待1秒
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return Result.failure(lastError!!)
|
return Result.failure(lastError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1105,7 +1111,7 @@ class CopyOrderTrackingService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. 检查每日亏损限制(需要计算今日已实现盈亏)
|
// 2. 检查每日亏损限制(需要计算今日已实现盈亏)
|
||||||
val todaySellRecords = sellMatchRecordRepository.findByCopyTradingId(copyTrading.id!!)
|
val todaySellRecords = sellMatchRecordRepository.findByCopyTradingId(copyTrading.id)
|
||||||
.filter { it.createdAt >= todayStart }
|
.filter { it.createdAt >= todayStart }
|
||||||
|
|
||||||
val todayRealizedPnl = todaySellRecords.sumOf { it.totalRealizedPnl.toSafeBigDecimal() }
|
val todayRealizedPnl = todaySellRecords.sumOf { it.totalRealizedPnl.toSafeBigDecimal() }
|
||||||
+45
-10
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.statistics
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.entity.*
|
import com.wrbug.polymarketbot.entity.*
|
||||||
@@ -13,6 +13,8 @@ import org.slf4j.LoggerFactory
|
|||||||
import org.springframework.data.domain.PageRequest
|
import org.springframework.data.domain.PageRequest
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.data.domain.Sort
|
import org.springframework.data.domain.Sort
|
||||||
|
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||||
|
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
@@ -30,7 +32,7 @@ class CopyTradingStatisticsService(
|
|||||||
private val accountRepository: AccountRepository,
|
private val accountRepository: AccountRepository,
|
||||||
private val leaderRepository: LeaderRepository,
|
private val leaderRepository: LeaderRepository,
|
||||||
private val accountService: AccountService,
|
private val accountService: AccountService,
|
||||||
private val blockchainService: com.wrbug.polymarketbot.service.BlockchainService
|
private val blockchainService: BlockchainService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(CopyTradingStatisticsService::class.java)
|
private val logger = LoggerFactory.getLogger(CopyTradingStatisticsService::class.java)
|
||||||
@@ -69,7 +71,10 @@ class CopyTradingStatisticsService(
|
|||||||
// 9. 计算未实现盈亏(使用链上实际持仓,而不是 remainingQuantity)
|
// 9. 计算未实现盈亏(使用链上实际持仓,而不是 remainingQuantity)
|
||||||
val unrealizedPnl = calculateUnrealizedPnl(buyOrders, currentPrice, actualPositions)
|
val unrealizedPnl = calculateUnrealizedPnl(buyOrders, currentPrice, actualPositions)
|
||||||
|
|
||||||
// 9. 构建响应
|
// 10. 计算持仓价值(使用链上实际持仓和当前价格)
|
||||||
|
val positionValue = calculatePositionValue(buyOrders, currentPrice, actualPositions)
|
||||||
|
|
||||||
|
// 11. 构建响应
|
||||||
val response = CopyTradingStatisticsResponse(
|
val response = CopyTradingStatisticsResponse(
|
||||||
copyTradingId = copyTradingId,
|
copyTradingId = copyTradingId,
|
||||||
accountId = copyTrading.accountId,
|
accountId = copyTrading.accountId,
|
||||||
@@ -85,7 +90,7 @@ class CopyTradingStatisticsService(
|
|||||||
totalSellOrders = statistics.totalSellOrders,
|
totalSellOrders = statistics.totalSellOrders,
|
||||||
totalSellAmount = statistics.totalSellAmount,
|
totalSellAmount = statistics.totalSellAmount,
|
||||||
currentPositionQuantity = statistics.currentPositionQuantity,
|
currentPositionQuantity = statistics.currentPositionQuantity,
|
||||||
currentPositionValue = calculatePositionValue(statistics.currentPositionQuantity, currentPrice),
|
currentPositionValue = positionValue,
|
||||||
totalRealizedPnl = statistics.totalRealizedPnl,
|
totalRealizedPnl = statistics.totalRealizedPnl,
|
||||||
totalUnrealizedPnl = unrealizedPnl,
|
totalUnrealizedPnl = unrealizedPnl,
|
||||||
totalPnl = (statistics.totalRealizedPnl.toSafeBigDecimal().add(unrealizedPnl.toSafeBigDecimal())).toString(),
|
totalPnl = (statistics.totalRealizedPnl.toSafeBigDecimal().add(unrealizedPnl.toSafeBigDecimal())).toString(),
|
||||||
@@ -105,7 +110,7 @@ class CopyTradingStatisticsService(
|
|||||||
fun getOrderList(request: OrderTrackingRequest): Result<OrderListResponse> {
|
fun getOrderList(request: OrderTrackingRequest): Result<OrderListResponse> {
|
||||||
return try {
|
return try {
|
||||||
// 1. 验证跟单关系
|
// 1. 验证跟单关系
|
||||||
val copyTrading = copyTradingRepository.findById(request.copyTradingId).orElse(null)
|
copyTradingRepository.findById(request.copyTradingId).orElse(null)
|
||||||
?: return Result.failure(IllegalArgumentException("跟单关系不存在: ${request.copyTradingId}"))
|
?: return Result.failure(IllegalArgumentException("跟单关系不存在: ${request.copyTradingId}"))
|
||||||
|
|
||||||
// 2. 根据类型查询
|
// 2. 根据类型查询
|
||||||
@@ -354,7 +359,7 @@ class CopyTradingStatisticsService(
|
|||||||
* 获取链上实际持仓
|
* 获取链上实际持仓
|
||||||
* 按 (marketId, outcomeIndex) 组合返回实际持仓数量
|
* 按 (marketId, outcomeIndex) 组合返回实际持仓数量
|
||||||
*/
|
*/
|
||||||
private suspend fun getActualPositions(account: com.wrbug.polymarketbot.entity.Account?): Map<String, BigDecimal> {
|
private suspend fun getActualPositions(account: Account?): Map<String, BigDecimal> {
|
||||||
val positions = mutableMapOf<String, BigDecimal>()
|
val positions = mutableMapOf<String, BigDecimal>()
|
||||||
|
|
||||||
if (account == null || account.proxyAddress.isBlank()) {
|
if (account == null || account.proxyAddress.isBlank()) {
|
||||||
@@ -424,11 +429,41 @@ class CopyTradingStatisticsService(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算持仓价值
|
* 计算持仓价值
|
||||||
|
* 使用链上实际持仓数量和当前市场价格计算
|
||||||
*/
|
*/
|
||||||
private fun calculatePositionValue(positionQuantity: String, currentPrices: Map<String, String>): String {
|
private fun calculatePositionValue(
|
||||||
// 这里简化处理,实际应该根据每个市场的持仓分别计算
|
buyOrders: List<CopyOrderTracking>,
|
||||||
// 暂时返回0,因为需要知道每个市场的持仓数量
|
currentPrices: Map<String, String>,
|
||||||
return "0"
|
actualPositions: Map<String, BigDecimal>
|
||||||
|
): String {
|
||||||
|
var totalPositionValue = BigDecimal.ZERO
|
||||||
|
|
||||||
|
for (order in buyOrders) {
|
||||||
|
// 如果没有 outcomeIndex,跳过(无法确定价格和持仓)
|
||||||
|
if (order.outcomeIndex == null) {
|
||||||
|
logger.warn("订单缺少 outcomeIndex,跳过持仓价值计算: orderId=${order.buyOrderId}, marketId=${order.marketId}")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 "marketId:outcomeIndex" 作为 key
|
||||||
|
val key = "${order.marketId}:${order.outcomeIndex}"
|
||||||
|
|
||||||
|
// 获取链上实际持仓数量(如果存在),否则使用 remainingQuantity
|
||||||
|
val actualQty = actualPositions[key] ?: order.remainingQuantity.toSafeBigDecimal()
|
||||||
|
|
||||||
|
// 如果实际持仓 <= 0,说明已全部卖出(包括手动卖出),跳过持仓价值计算
|
||||||
|
if (actualQty.lte(BigDecimal.ZERO)) continue
|
||||||
|
|
||||||
|
// 获取当前市场价格
|
||||||
|
val currentPrice = currentPrices[key]?.toSafeBigDecimal()
|
||||||
|
?: continue // 如果没有当前价格,跳过
|
||||||
|
|
||||||
|
// 计算持仓价值:持仓数量 × 当前价格
|
||||||
|
val positionValue = actualQty.multi(currentPrice)
|
||||||
|
totalPositionValue = totalPositionValue.add(positionValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalPositionValue.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.copytrading.templates
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.entity.CopyTradingTemplate
|
import com.wrbug.polymarketbot.entity.CopyTradingTemplate
|
||||||
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.ApiHealthCheckDto
|
import com.wrbug.polymarketbot.dto.ApiHealthCheckDto
|
||||||
import com.wrbug.polymarketbot.dto.ApiHealthCheckResponse
|
import com.wrbug.polymarketbot.dto.ApiHealthCheckResponse
|
||||||
@@ -12,6 +12,8 @@ import org.springframework.beans.BeansException
|
|||||||
import org.springframework.context.ApplicationContext
|
import org.springframework.context.ApplicationContext
|
||||||
import org.springframework.context.ApplicationContextAware
|
import org.springframework.context.ApplicationContextAware
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingWebSocketService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
+3
-1
@@ -1,8 +1,10 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.*
|
import com.wrbug.polymarketbot.dto.*
|
||||||
import com.wrbug.polymarketbot.entity.ProxyConfig
|
import com.wrbug.polymarketbot.entity.ProxyConfig
|
||||||
import com.wrbug.polymarketbot.repository.ProxyConfigRepository
|
import com.wrbug.polymarketbot.repository.ProxyConfigRepository
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingWebSocketService
|
||||||
|
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||||
import com.wrbug.polymarketbot.util.ProxyConfigProvider
|
import com.wrbug.polymarketbot.util.ProxyConfigProvider
|
||||||
import com.wrbug.polymarketbot.util.TrustAllHostnameVerifier
|
import com.wrbug.polymarketbot.util.TrustAllHostnameVerifier
|
||||||
import com.wrbug.polymarketbot.util.createSSLSocketFactory
|
import com.wrbug.polymarketbot.util.createSSLSocketFactory
|
||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.api.BuilderRelayerApi
|
import com.wrbug.polymarketbot.api.BuilderRelayerApi
|
||||||
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
||||||
@@ -802,10 +802,10 @@ class RelayClientService(
|
|||||||
safeTxs: List<SafeTransaction>
|
safeTxs: List<SafeTransaction>
|
||||||
): Result<String> {
|
): Result<String> {
|
||||||
// 批量执行:将多个交易合并为一个 execTransaction 调用
|
// 批量执行:将多个交易合并为一个 execTransaction 调用
|
||||||
// 当前实现:委托给 BlockchainService
|
// 当前实现:委托给 com.wrbug.polymarketbot.service.common.BlockchainService
|
||||||
return Result.failure(
|
return Result.failure(
|
||||||
UnsupportedOperationException(
|
UnsupportedOperationException(
|
||||||
"批量 Gasless 执行暂未实现。请使用 BlockchainService.redeemPositions() 方法。"
|
"批量 Gasless 执行暂未实现。请使用 com.wrbug.polymarketbot.service.common.BlockchainService.redeemPositions() 方法。"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.SystemConfigDto
|
import com.wrbug.polymarketbot.dto.SystemConfigDto
|
||||||
import com.wrbug.polymarketbot.dto.SystemConfigUpdateRequest
|
import com.wrbug.polymarketbot.dto.SystemConfigUpdateRequest
|
||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||||
import com.wrbug.polymarketbot.dto.NotificationConfigData
|
import com.wrbug.polymarketbot.dto.NotificationConfigData
|
||||||
import com.wrbug.polymarketbot.dto.TelegramConfigData
|
import com.wrbug.polymarketbot.dto.TelegramConfigData
|
||||||
import com.wrbug.polymarketbot.util.createClient
|
import com.wrbug.polymarketbot.util.createClient
|
||||||
@@ -65,7 +66,7 @@ class TelegramNotificationService(
|
|||||||
side: String,
|
side: String,
|
||||||
accountName: String? = null,
|
accountName: String? = null,
|
||||||
walletAddress: String? = null,
|
walletAddress: String? = null,
|
||||||
clobApi: com.wrbug.polymarketbot.api.PolymarketClobApi? = null,
|
clobApi: PolymarketClobApi? = null,
|
||||||
apiKey: String? = null,
|
apiKey: String? = null,
|
||||||
apiSecret: String? = null,
|
apiSecret: String? = null,
|
||||||
apiPassphrase: String? = null,
|
apiPassphrase: String? = null,
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package com.wrbug.polymarketbot.service
|
package com.wrbug.polymarketbot.service.system
|
||||||
|
|
||||||
import com.wrbug.polymarketbot.dto.UserCreateRequest
|
import com.wrbug.polymarketbot.dto.UserCreateRequest
|
||||||
import com.wrbug.polymarketbot.dto.UserDto
|
import com.wrbug.polymarketbot.dto.UserDto
|
||||||
+1
-1
@@ -3,7 +3,7 @@ package com.wrbug.polymarketbot.websocket
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
||||||
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
||||||
import com.wrbug.polymarketbot.service.WebSocketSubscriptionService
|
import com.wrbug.polymarketbot.service.common.WebSocketSubscriptionService
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import jakarta.annotation.PreDestroy
|
import jakarta.annotation.PreDestroy
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
|||||||
@@ -145,31 +145,31 @@ export const apiService = {
|
|||||||
* 获取用户列表
|
* 获取用户列表
|
||||||
*/
|
*/
|
||||||
list: () =>
|
list: () =>
|
||||||
apiClient.post<ApiResponse<any[]>>('/users/list', {}),
|
apiClient.post<ApiResponse<any[]>>('/system/users/list', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建用户
|
* 创建用户
|
||||||
*/
|
*/
|
||||||
create: (data: { username: string; password: string }) =>
|
create: (data: { username: string; password: string }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/users/create', data),
|
apiClient.post<ApiResponse<any>>('/system/users/create', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新用户密码
|
* 更新用户密码
|
||||||
*/
|
*/
|
||||||
updatePassword: (data: { userId: number; newPassword: string }) =>
|
updatePassword: (data: { userId: number; newPassword: string }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/users/update-password', data),
|
apiClient.post<ApiResponse<void>>('/system/users/update-password', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除用户
|
* 删除用户
|
||||||
*/
|
*/
|
||||||
delete: (data: { userId: number }) =>
|
delete: (data: { userId: number }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/users/delete', data),
|
apiClient.post<ApiResponse<void>>('/system/users/delete', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户修改自己的密码
|
* 用户修改自己的密码
|
||||||
*/
|
*/
|
||||||
updateOwnPassword: (data: { newPassword: string }) =>
|
updateOwnPassword: (data: { newPassword: string }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/users/update-own-password', data)
|
apiClient.post<ApiResponse<void>>('/system/users/update-own-password', data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -203,61 +203,61 @@ export const apiService = {
|
|||||||
* 导入账户
|
* 导入账户
|
||||||
*/
|
*/
|
||||||
import: (data: any) =>
|
import: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/import', data),
|
apiClient.post<ApiResponse<any>>('/accounts/import', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新账户
|
* 更新账户
|
||||||
*/
|
*/
|
||||||
update: (data: any) =>
|
update: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/update', data),
|
apiClient.post<ApiResponse<any>>('/accounts/update', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除账户
|
* 删除账户
|
||||||
*/
|
*/
|
||||||
delete: (data: { accountId: number }) =>
|
delete: (data: { accountId: number }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/copy-trading/accounts/delete', data),
|
apiClient.post<ApiResponse<void>>('/accounts/delete', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询账户列表
|
* 查询账户列表
|
||||||
*/
|
*/
|
||||||
list: () =>
|
list: () =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/list', {}),
|
apiClient.post<ApiResponse<any>>('/accounts/list', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询账户详情
|
* 查询账户详情
|
||||||
*/
|
*/
|
||||||
detail: (data: { accountId?: number }) =>
|
detail: (data: { accountId?: number }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/detail', data),
|
apiClient.post<ApiResponse<any>>('/accounts/detail', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询账户余额
|
* 查询账户余额
|
||||||
*/
|
*/
|
||||||
balance: (data: { accountId?: number }) =>
|
balance: (data: { accountId?: number }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/balance', data),
|
apiClient.post<ApiResponse<any>>('/accounts/balance', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询所有账户的仓位列表
|
* 查询所有账户的仓位列表
|
||||||
*/
|
*/
|
||||||
positionsList: () =>
|
positionsList: () =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/list', {}),
|
apiClient.post<ApiResponse<any>>('/accounts/positions/list', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 卖出仓位
|
* 卖出仓位
|
||||||
*/
|
*/
|
||||||
sellPosition: (data: any) =>
|
sellPosition: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/sell', data),
|
apiClient.post<ApiResponse<any>>('/accounts/positions/sell', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取可赎回仓位统计
|
* 获取可赎回仓位统计
|
||||||
*/
|
*/
|
||||||
getRedeemableSummary: (data: { accountId?: number }) =>
|
getRedeemableSummary: (data: { accountId?: number }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/redeemable-summary', data),
|
apiClient.post<ApiResponse<any>>('/accounts/positions/redeemable-summary', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 赎回仓位
|
* 赎回仓位
|
||||||
*/
|
*/
|
||||||
redeemPositions: (data: any) =>
|
redeemPositions: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/redeem', data),
|
apiClient.post<ApiResponse<any>>('/accounts/positions/redeem', data),
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -269,13 +269,13 @@ export const apiService = {
|
|||||||
* 获取市场价格(通过 Gamma API)
|
* 获取市场价格(通过 Gamma API)
|
||||||
*/
|
*/
|
||||||
getMarketPrice: (data: { marketId: string; outcomeIndex?: number }) =>
|
getMarketPrice: (data: { marketId: string; outcomeIndex?: number }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/markets/price', data),
|
apiClient.post<ApiResponse<any>>('/markets/price', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取最新价(从订单表获取,供前端下单时显示)
|
* 获取最新价(从订单表获取,供前端下单时显示)
|
||||||
*/
|
*/
|
||||||
getLatestPrice: (data: { tokenId: string }) =>
|
getLatestPrice: (data: { tokenId: string }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/markets/latest-price', data)
|
apiClient.post<ApiResponse<any>>('/markets/latest-price', data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,37 +365,37 @@ export const apiService = {
|
|||||||
* 2. 不提供 templateId:手动输入所有配置参数
|
* 2. 不提供 templateId:手动输入所有配置参数
|
||||||
*/
|
*/
|
||||||
create: (data: any) =>
|
create: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/create', data),
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/create', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新跟单配置
|
* 更新跟单配置
|
||||||
*/
|
*/
|
||||||
update: (data: any) =>
|
update: (data: any) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/update', data),
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/update', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询跟单列表
|
* 查询跟单列表
|
||||||
*/
|
*/
|
||||||
list: (data: { accountId?: number; leaderId?: number; enabled?: boolean } = {}) =>
|
list: (data: { accountId?: number; leaderId?: number; enabled?: boolean } = {}) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/list', data),
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/list', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新跟单状态(兼容旧接口)
|
* 更新跟单状态(兼容旧接口)
|
||||||
*/
|
*/
|
||||||
updateStatus: (data: { copyTradingId: number; enabled: boolean }) =>
|
updateStatus: (data: { copyTradingId: number; enabled: boolean }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/update-status', data),
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/update-status', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除跟单
|
* 删除跟单
|
||||||
*/
|
*/
|
||||||
delete: (data: { copyTradingId: number }) =>
|
delete: (data: { copyTradingId: number }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/copy-trading/delete', data),
|
apiClient.post<ApiResponse<void>>('/copy-trading/configs/delete', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询钱包绑定的跟单配置(兼容旧接口)
|
* 查询钱包绑定的跟单配置(兼容旧接口)
|
||||||
*/
|
*/
|
||||||
getAccountTemplates: (data: { accountId: number }) =>
|
getAccountTemplates: (data: { accountId: number }) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/account-templates', data),
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/account-templates', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询被过滤订单列表
|
* 查询被过滤订单列表
|
||||||
@@ -408,7 +408,7 @@ export const apiService = {
|
|||||||
startTime?: number
|
startTime?: number
|
||||||
endTime?: number
|
endTime?: number
|
||||||
}) =>
|
}) =>
|
||||||
apiClient.post<ApiResponse<any>>('/copy-trading/filtered-orders', data)
|
apiClient.post<ApiResponse<any>>('/copy-trading/configs/filtered-orders', data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -476,13 +476,13 @@ export const apiService = {
|
|||||||
* 获取当前代理配置
|
* 获取当前代理配置
|
||||||
*/
|
*/
|
||||||
get: () =>
|
get: () =>
|
||||||
apiClient.post<ApiResponse<any>>('/proxy-config/get', {}),
|
apiClient.post<ApiResponse<any>>('/system/proxy/get', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有代理配置
|
* 获取所有代理配置
|
||||||
*/
|
*/
|
||||||
list: () =>
|
list: () =>
|
||||||
apiClient.post<ApiResponse<any[]>>('/proxy-config/list', {}),
|
apiClient.post<ApiResponse<any[]>>('/system/proxy/list', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存 HTTP 代理配置
|
* 保存 HTTP 代理配置
|
||||||
@@ -494,7 +494,7 @@ export const apiService = {
|
|||||||
username?: string
|
username?: string
|
||||||
password?: string
|
password?: string
|
||||||
}) =>
|
}) =>
|
||||||
apiClient.post<ApiResponse<any>>('/proxy-config/http/save', data),
|
apiClient.post<ApiResponse<any>>('/system/proxy/http/save', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查代理是否可用
|
* 检查代理是否可用
|
||||||
@@ -504,13 +504,13 @@ export const apiService = {
|
|||||||
success: boolean
|
success: boolean
|
||||||
message: string
|
message: string
|
||||||
responseTime?: number
|
responseTime?: number
|
||||||
}>>('/proxy-config/check', {}),
|
}>>('/system/proxy/check', {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除代理配置
|
* 删除代理配置
|
||||||
*/
|
*/
|
||||||
delete: (data: { id: number }) =>
|
delete: (data: { id: number }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/proxy-config/delete', data),
|
apiClient.post<ApiResponse<void>>('/system/proxy/delete', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查所有 API 的健康状态
|
* 检查所有 API 的健康状态
|
||||||
@@ -524,7 +524,7 @@ export const apiService = {
|
|||||||
message: string
|
message: string
|
||||||
responseTime?: number
|
responseTime?: number
|
||||||
}>
|
}>
|
||||||
}>>('/proxy-config/api-health-check', {})
|
}>>('/system/proxy/api-health-check', {})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -535,49 +535,49 @@ export const apiService = {
|
|||||||
* 获取配置列表
|
* 获取配置列表
|
||||||
*/
|
*/
|
||||||
list: (data?: { type?: string }) =>
|
list: (data?: { type?: string }) =>
|
||||||
apiClient.post<ApiResponse<NotificationConfig[]>>('/notifications/configs/list', data || {}),
|
apiClient.post<ApiResponse<NotificationConfig[]>>('/system/notifications/configs/list', data || {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取配置详情
|
* 获取配置详情
|
||||||
*/
|
*/
|
||||||
detail: (data: { id: number }) =>
|
detail: (data: { id: number }) =>
|
||||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/detail', data),
|
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/detail', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建配置
|
* 创建配置
|
||||||
*/
|
*/
|
||||||
create: (data: NotificationConfigRequest) =>
|
create: (data: NotificationConfigRequest) =>
|
||||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/create', data),
|
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/create', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新配置
|
* 更新配置
|
||||||
*/
|
*/
|
||||||
update: (data: NotificationConfigUpdateRequest) =>
|
update: (data: NotificationConfigUpdateRequest) =>
|
||||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/update', data),
|
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/update', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新启用状态
|
* 更新启用状态
|
||||||
*/
|
*/
|
||||||
updateEnabled: (data: { id: number; enabled: boolean }) =>
|
updateEnabled: (data: { id: number; enabled: boolean }) =>
|
||||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/update-enabled', data),
|
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/update-enabled', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除配置
|
* 删除配置
|
||||||
*/
|
*/
|
||||||
delete: (data: { id: number }) =>
|
delete: (data: { id: number }) =>
|
||||||
apiClient.post<ApiResponse<void>>('/notifications/configs/delete', data),
|
apiClient.post<ApiResponse<void>>('/system/notifications/configs/delete', data),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试通知
|
* 测试通知
|
||||||
*/
|
*/
|
||||||
test: (data?: { message?: string }) =>
|
test: (data?: { message?: string }) =>
|
||||||
apiClient.post<ApiResponse<boolean>>('/notifications/test', data || {}),
|
apiClient.post<ApiResponse<boolean>>('/system/notifications/test', data || {}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 Telegram Chat IDs
|
* 获取 Telegram Chat IDs
|
||||||
*/
|
*/
|
||||||
getTelegramChatIds: (data: { botToken: string }) =>
|
getTelegramChatIds: (data: { botToken: string }) =>
|
||||||
apiClient.post<ApiResponse<string[]>>('/notifications/telegram/get-chat-ids', data)
|
apiClient.post<ApiResponse<string[]>>('/system/notifications/telegram/get-chat-ids', data)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user