Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
e99b344b
Commit
e99b344b
authored
Dec 19, 2025
by
Forest
Browse files
refactor(backend): 引入端口接口模式
parent
7fd94ab7
Changes
45
Hide whitespace changes
Inline
Side-by-side
backend/cmd/server/wire_gen.go
View file @
e99b344b
...
...
@@ -57,32 +57,21 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
usageService
:=
service
.
NewUsageService
(
usageLogRepository
,
userRepository
)
usageHandler
:=
handler
.
NewUsageHandler
(
usageService
,
usageLogRepository
,
apiKeyService
)
redeemCodeRepository
:=
repository
.
NewRedeemCodeRepository
(
db
)
accountRepository
:=
repository
.
NewAccountRepository
(
db
)
proxyRepository
:=
repository
.
NewProxyRepository
(
db
)
repositories
:=
&
repository
.
Repositories
{
User
:
userRepository
,
ApiKey
:
apiKeyRepository
,
Group
:
groupRepository
,
Account
:
accountRepository
,
Proxy
:
proxyRepository
,
RedeemCode
:
redeemCodeRepository
,
UsageLog
:
usageLogRepository
,
Setting
:
settingRepository
,
UserSubscription
:
userSubscriptionRepository
,
}
billingCacheService
:=
service
.
NewBillingCacheService
(
client
,
userRepository
,
userSubscriptionRepository
)
subscriptionService
:=
service
.
NewSubscriptionService
(
r
epositor
ies
,
billingCacheService
)
subscriptionService
:=
service
.
NewSubscriptionService
(
groupR
epositor
y
,
userSubscriptionRepository
,
billingCacheService
)
redeemService
:=
service
.
NewRedeemService
(
redeemCodeRepository
,
userRepository
,
subscriptionService
,
client
,
billingCacheService
)
redeemHandler
:=
handler
.
NewRedeemHandler
(
redeemService
)
subscriptionHandler
:=
handler
.
NewSubscriptionHandler
(
subscriptionService
)
adminService
:=
service
.
NewAdminService
(
repositories
,
billingCacheService
)
accountRepository
:=
repository
.
NewAccountRepository
(
db
)
proxyRepository
:=
repository
.
NewProxyRepository
(
db
)
adminService
:=
service
.
NewAdminService
(
userRepository
,
groupRepository
,
accountRepository
,
proxyRepository
,
apiKeyRepository
,
redeemCodeRepository
,
usageLogRepository
,
userSubscriptionRepository
,
billingCacheService
)
dashboardHandler
:=
admin
.
NewDashboardHandler
(
adminService
,
usageLogRepository
)
adminUserHandler
:=
admin
.
NewUserHandler
(
adminService
)
groupHandler
:=
admin
.
NewGroupHandler
(
adminService
)
oAuthService
:=
service
.
NewOAuthService
(
proxyRepository
)
rateLimitService
:=
service
.
NewRateLimitService
(
r
epositor
ies
,
configConfig
)
accountUsageService
:=
service
.
NewAccountUsageService
(
repositories
,
oAuthService
)
accountTestService
:=
service
.
NewAccountTestService
(
r
epositor
ies
,
oAuthService
)
rateLimitService
:=
service
.
NewRateLimitService
(
accountR
epositor
y
,
configConfig
)
accountUsageService
:=
service
.
NewAccountUsageService
(
accountRepository
,
usageLogRepository
,
oAuthService
)
accountTestService
:=
service
.
NewAccountTestService
(
accountR
epositor
y
,
oAuthService
)
accountHandler
:=
admin
.
NewAccountHandler
(
adminService
,
oAuthService
,
rateLimitService
,
accountUsageService
,
accountTestService
)
oAuthHandler
:=
admin
.
NewOAuthHandler
(
oAuthService
,
adminService
)
proxyHandler
:=
admin
.
NewProxyHandler
(
adminService
)
...
...
@@ -98,7 +87,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
}
billingService
:=
service
.
NewBillingService
(
configConfig
,
pricingService
)
identityService
:=
service
.
NewIdentityService
(
client
)
gatewayService
:=
service
.
NewGatewayService
(
repositories
,
client
,
configConfig
,
oAuthService
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
)
gatewayService
:=
service
.
NewGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
client
,
configConfig
,
oAuthService
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
)
concurrencyService
:=
service
.
NewConcurrencyService
(
client
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
userService
,
concurrencyService
,
billingCacheService
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
...
...
@@ -132,6 +121,17 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
Concurrency
:
concurrencyService
,
Identity
:
identityService
,
}
repositories
:=
&
repository
.
Repositories
{
User
:
userRepository
,
ApiKey
:
apiKeyRepository
,
Group
:
groupRepository
,
Account
:
accountRepository
,
Proxy
:
proxyRepository
,
RedeemCode
:
redeemCodeRepository
,
UsageLog
:
usageLogRepository
,
Setting
:
settingRepository
,
UserSubscription
:
userSubscriptionRepository
,
}
engine
:=
server
.
ProvideRouter
(
configConfig
,
handlers
,
services
,
repositories
)
httpServer
:=
server
.
ProvideHTTPServer
(
configConfig
,
engine
)
v
:=
provideCleanup
(
db
,
client
,
services
)
...
...
backend/internal/handler/admin/subscription_handler.go
View file @
e99b344b
...
...
@@ -4,15 +4,15 @@ import (
"strconv"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"sub2api/internal/pkg/response"
"sub2api/internal/repository"
"sub2api/internal/service"
"github.com/gin-gonic/gin"
)
// toResponsePagination converts
repository
.PaginationResult to response.PaginationResult
func
toResponsePagination
(
p
*
repository
.
PaginationResult
)
*
response
.
PaginationResult
{
// toResponsePagination converts
pagination
.PaginationResult to response.PaginationResult
func
toResponsePagination
(
p
*
pagination
.
PaginationResult
)
*
response
.
PaginationResult
{
if
p
==
nil
{
return
nil
}
...
...
backend/internal/handler/admin/usage_handler.go
View file @
e99b344b
...
...
@@ -4,6 +4,7 @@ import (
"strconv"
"time"
"sub2api/internal/pkg/pagination"
"sub2api/internal/pkg/response"
"sub2api/internal/pkg/timezone"
"sub2api/internal/repository"
...
...
@@ -14,10 +15,10 @@ import (
// UsageHandler handles admin usage-related requests
type
UsageHandler
struct
{
usageRepo
*
repository
.
UsageLogRepository
apiKeyRepo
*
repository
.
ApiKeyRepository
usageService
*
service
.
UsageService
adminService
service
.
AdminService
usageRepo
*
repository
.
UsageLogRepository
apiKeyRepo
*
repository
.
ApiKeyRepository
usageService
*
service
.
UsageService
adminService
service
.
AdminService
}
// NewUsageHandler creates a new admin usage handler
...
...
@@ -82,7 +83,7 @@ func (h *UsageHandler) List(c *gin.Context) {
endTime
=
&
t
}
params
:=
repository
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
params
:=
pagination
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
filters
:=
repository
.
UsageLogFilters
{
UserID
:
userID
,
ApiKeyID
:
apiKeyID
,
...
...
backend/internal/handler/api_key_handler.go
View file @
e99b344b
...
...
@@ -4,8 +4,8 @@ import (
"strconv"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"sub2api/internal/pkg/response"
"sub2api/internal/repository"
"sub2api/internal/service"
"github.com/gin-gonic/gin"
...
...
@@ -53,7 +53,7 @@ func (h *APIKeyHandler) List(c *gin.Context) {
}
page
,
pageSize
:=
response
.
ParsePagination
(
c
)
params
:=
repository
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
params
:=
pagination
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
keys
,
result
,
err
:=
h
.
apiKeyService
.
List
(
c
.
Request
.
Context
(),
user
.
ID
,
params
)
if
err
!=
nil
{
...
...
backend/internal/handler/usage_handler.go
View file @
e99b344b
...
...
@@ -5,6 +5,7 @@ import (
"time"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"sub2api/internal/pkg/response"
"sub2api/internal/pkg/timezone"
"sub2api/internal/repository"
...
...
@@ -68,9 +69,9 @@ func (h *UsageHandler) List(c *gin.Context) {
apiKeyID
=
id
}
params
:=
repository
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
params
:=
pagination
.
PaginationParams
{
Page
:
page
,
PageSize
:
pageSize
}
var
records
[]
model
.
UsageLog
var
result
*
repository
.
PaginationResult
var
result
*
pagination
.
PaginationResult
var
err
error
if
apiKeyID
>
0
{
...
...
@@ -362,7 +363,7 @@ func (h *UsageHandler) DashboardApiKeysUsage(c *gin.Context) {
}
// Verify ownership of all requested API keys
userApiKeys
,
_
,
err
:=
h
.
apiKeyService
.
List
(
c
.
Request
.
Context
(),
user
.
ID
,
repository
.
PaginationParams
{
Page
:
1
,
PageSize
:
1000
})
userApiKeys
,
_
,
err
:=
h
.
apiKeyService
.
List
(
c
.
Request
.
Context
(),
user
.
ID
,
pagination
.
PaginationParams
{
Page
:
1
,
PageSize
:
1000
})
if
err
!=
nil
{
response
.
InternalError
(
c
,
"Failed to verify API key ownership"
)
return
...
...
backend/internal/pkg/pagination/pagination.go
0 → 100644
View file @
e99b344b
package
pagination
// PaginationParams 分页参数
type
PaginationParams
struct
{
Page
int
PageSize
int
}
// PaginationResult 分页结果
type
PaginationResult
struct
{
Total
int64
Page
int
PageSize
int
Pages
int
}
// DefaultPagination 默认分页参数
func
DefaultPagination
()
PaginationParams
{
return
PaginationParams
{
Page
:
1
,
PageSize
:
20
,
}
}
// Offset 计算偏移量
func
(
p
PaginationParams
)
Offset
()
int
{
if
p
.
Page
<
1
{
p
.
Page
=
1
}
return
(
p
.
Page
-
1
)
*
p
.
PageSize
}
// Limit 获取限制数
func
(
p
PaginationParams
)
Limit
()
int
{
if
p
.
PageSize
<
1
{
return
20
}
if
p
.
PageSize
>
100
{
return
100
}
return
p
.
PageSize
}
backend/internal/pkg/response/response.go
View file @
e99b344b
...
...
@@ -90,7 +90,7 @@ func Paginated(c *gin.Context, items interface{}, total int64, page, pageSize in
})
}
// PaginationResult 分页结果(与
repository
.PaginationResult兼容)
// PaginationResult 分页结果(与
pagination
.PaginationResult兼容)
type
PaginationResult
struct
{
Total
int64
Page
int
...
...
backend/internal/pkg/usagestats/account_stats.go
0 → 100644
View file @
e99b344b
package
usagestats
// AccountStats 账号使用统计
type
AccountStats
struct
{
Requests
int64
`json:"requests"`
Tokens
int64
`json:"tokens"`
Cost
float64
`json:"cost"`
}
backend/internal/repository/account_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"time"
"gorm.io/gorm"
...
...
@@ -47,12 +48,12 @@ func (r *AccountRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
Account
{},
id
)
.
Error
}
func
(
r
*
AccountRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
)
([]
model
.
Account
,
*
PaginationResult
,
error
)
{
func
(
r
*
AccountRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
Account
,
*
pagination
.
PaginationResult
,
error
)
{
return
r
.
ListWithFilters
(
ctx
,
params
,
""
,
""
,
""
,
""
)
}
// ListWithFilters lists accounts with optional filtering by platform, type, status, and search query
func
(
r
*
AccountRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
platform
,
accountType
,
status
,
search
string
)
([]
model
.
Account
,
*
PaginationResult
,
error
)
{
func
(
r
*
AccountRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
platform
,
accountType
,
status
,
search
string
)
([]
model
.
Account
,
*
pagination
.
PaginationResult
,
error
)
{
var
accounts
[]
model
.
Account
var
total
int64
...
...
@@ -94,7 +95,7 @@ func (r *AccountRepository) ListWithFilters(ctx context.Context, params Paginati
pages
++
}
return
accounts
,
&
PaginationResult
{
return
accounts
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -226,7 +227,7 @@ func (r *AccountRepository) SetRateLimited(ctx context.Context, id int64, resetA
now
:=
time
.
Now
()
return
r
.
db
.
WithContext
(
ctx
)
.
Model
(
&
model
.
Account
{})
.
Where
(
"id = ?"
,
id
)
.
Updates
(
map
[
string
]
interface
{}{
"rate_limited_at"
:
now
,
"rate_limited_at"
:
now
,
"rate_limit_reset_at"
:
resetAt
,
})
.
Error
}
...
...
backend/internal/repository/api_key_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"gorm.io/gorm"
)
...
...
@@ -45,7 +46,7 @@ func (r *ApiKeyRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
ApiKey
{},
id
)
.
Error
}
func
(
r
*
ApiKeyRepository
)
ListByUserID
(
ctx
context
.
Context
,
userID
int64
,
params
PaginationParams
)
([]
model
.
ApiKey
,
*
PaginationResult
,
error
)
{
func
(
r
*
ApiKeyRepository
)
ListByUserID
(
ctx
context
.
Context
,
userID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
ApiKey
,
*
pagination
.
PaginationResult
,
error
)
{
var
keys
[]
model
.
ApiKey
var
total
int64
...
...
@@ -64,7 +65,7 @@ func (r *ApiKeyRepository) ListByUserID(ctx context.Context, userID int64, param
pages
++
}
return
keys
,
&
PaginationResult
{
return
keys
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -84,7 +85,7 @@ func (r *ApiKeyRepository) ExistsByKey(ctx context.Context, key string) (bool, e
return
count
>
0
,
err
}
func
(
r
*
ApiKeyRepository
)
ListByGroupID
(
ctx
context
.
Context
,
groupID
int64
,
params
PaginationParams
)
([]
model
.
ApiKey
,
*
PaginationResult
,
error
)
{
func
(
r
*
ApiKeyRepository
)
ListByGroupID
(
ctx
context
.
Context
,
groupID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
ApiKey
,
*
pagination
.
PaginationResult
,
error
)
{
var
keys
[]
model
.
ApiKey
var
total
int64
...
...
@@ -103,7 +104,7 @@ func (r *ApiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, par
pages
++
}
return
keys
,
&
PaginationResult
{
return
keys
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
backend/internal/repository/group_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"gorm.io/gorm"
)
...
...
@@ -36,12 +37,12 @@ func (r *GroupRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
Group
{},
id
)
.
Error
}
func
(
r
*
GroupRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
)
([]
model
.
Group
,
*
PaginationResult
,
error
)
{
func
(
r
*
GroupRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
Group
,
*
pagination
.
PaginationResult
,
error
)
{
return
r
.
ListWithFilters
(
ctx
,
params
,
""
,
""
,
nil
)
}
// ListWithFilters lists groups with optional filtering by platform, status, and is_exclusive
func
(
r
*
GroupRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
platform
,
status
string
,
isExclusive
*
bool
)
([]
model
.
Group
,
*
PaginationResult
,
error
)
{
func
(
r
*
GroupRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
platform
,
status
string
,
isExclusive
*
bool
)
([]
model
.
Group
,
*
pagination
.
PaginationResult
,
error
)
{
var
groups
[]
model
.
Group
var
total
int64
...
...
@@ -77,7 +78,7 @@ func (r *GroupRepository) ListWithFilters(ctx context.Context, params Pagination
pages
++
}
return
groups
,
&
PaginationResult
{
return
groups
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
backend/internal/repository/proxy_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"gorm.io/gorm"
)
...
...
@@ -36,12 +37,12 @@ func (r *ProxyRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
Proxy
{},
id
)
.
Error
}
func
(
r
*
ProxyRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
)
([]
model
.
Proxy
,
*
PaginationResult
,
error
)
{
func
(
r
*
ProxyRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
Proxy
,
*
pagination
.
PaginationResult
,
error
)
{
return
r
.
ListWithFilters
(
ctx
,
params
,
""
,
""
,
""
)
}
// ListWithFilters lists proxies with optional filtering by protocol, status, and search query
func
(
r
*
ProxyRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
protocol
,
status
,
search
string
)
([]
model
.
Proxy
,
*
PaginationResult
,
error
)
{
func
(
r
*
ProxyRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
protocol
,
status
,
search
string
)
([]
model
.
Proxy
,
*
pagination
.
PaginationResult
,
error
)
{
var
proxies
[]
model
.
Proxy
var
total
int64
...
...
@@ -72,7 +73,7 @@ func (r *ProxyRepository) ListWithFilters(ctx context.Context, params Pagination
pages
++
}
return
proxies
,
&
PaginationResult
{
return
proxies
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
backend/internal/repository/redeem_code_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"time"
"gorm.io/gorm"
...
...
@@ -46,12 +47,12 @@ func (r *RedeemCodeRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
RedeemCode
{},
id
)
.
Error
}
func
(
r
*
RedeemCodeRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
)
([]
model
.
RedeemCode
,
*
PaginationResult
,
error
)
{
func
(
r
*
RedeemCodeRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
RedeemCode
,
*
pagination
.
PaginationResult
,
error
)
{
return
r
.
ListWithFilters
(
ctx
,
params
,
""
,
""
,
""
)
}
// ListWithFilters lists redeem codes with optional filtering by type, status, and search query
func
(
r
*
RedeemCodeRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
codeType
,
status
,
search
string
)
([]
model
.
RedeemCode
,
*
PaginationResult
,
error
)
{
func
(
r
*
RedeemCodeRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
codeType
,
status
,
search
string
)
([]
model
.
RedeemCode
,
*
pagination
.
PaginationResult
,
error
)
{
var
codes
[]
model
.
RedeemCode
var
total
int64
...
...
@@ -82,7 +83,7 @@ func (r *RedeemCodeRepository) ListWithFilters(ctx context.Context, params Pagin
pages
++
}
return
codes
,
&
PaginationResult
{
return
codes
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
backend/internal/repository/repository.go
View file @
e99b344b
...
...
@@ -12,44 +12,3 @@ type Repositories struct {
Setting
*
SettingRepository
UserSubscription
*
UserSubscriptionRepository
}
// PaginationParams 分页参数
type
PaginationParams
struct
{
Page
int
PageSize
int
}
// PaginationResult 分页结果
type
PaginationResult
struct
{
Total
int64
Page
int
PageSize
int
Pages
int
}
// DefaultPagination 默认分页参数
func
DefaultPagination
()
PaginationParams
{
return
PaginationParams
{
Page
:
1
,
PageSize
:
20
,
}
}
// Offset 计算偏移量
func
(
p
PaginationParams
)
Offset
()
int
{
if
p
.
Page
<
1
{
p
.
Page
=
1
}
return
(
p
.
Page
-
1
)
*
p
.
PageSize
}
// Limit 获取限制数
func
(
p
PaginationParams
)
Limit
()
int
{
if
p
.
PageSize
<
1
{
return
20
}
if
p
.
PageSize
>
100
{
return
100
}
return
p
.
PageSize
}
backend/internal/repository/usage_log_repo.go
View file @
e99b344b
...
...
@@ -3,7 +3,9 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"sub2api/internal/pkg/timezone"
"sub2api/internal/pkg/usagestats"
"time"
"gorm.io/gorm"
...
...
@@ -30,7 +32,7 @@ func (r *UsageLogRepository) GetByID(ctx context.Context, id int64) (*model.Usag
return
&
log
,
nil
}
func
(
r
*
UsageLogRepository
)
ListByUser
(
ctx
context
.
Context
,
userID
int64
,
params
PaginationParams
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByUser
(
ctx
context
.
Context
,
userID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
var
total
int64
...
...
@@ -49,7 +51,7 @@ func (r *UsageLogRepository) ListByUser(ctx context.Context, userID int64, param
pages
++
}
return
logs
,
&
PaginationResult
{
return
logs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -57,7 +59,7 @@ func (r *UsageLogRepository) ListByUser(ctx context.Context, userID int64, param
},
nil
}
func
(
r
*
UsageLogRepository
)
ListByApiKey
(
ctx
context
.
Context
,
apiKeyID
int64
,
params
PaginationParams
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByApiKey
(
ctx
context
.
Context
,
apiKeyID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
var
total
int64
...
...
@@ -76,7 +78,7 @@ func (r *UsageLogRepository) ListByApiKey(ctx context.Context, apiKeyID int64, p
pages
++
}
return
logs
,
&
PaginationResult
{
return
logs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -270,7 +272,7 @@ func (r *UsageLogRepository) GetDashboardStats(ctx context.Context) (*DashboardS
return
&
stats
,
nil
}
func
(
r
*
UsageLogRepository
)
ListByAccount
(
ctx
context
.
Context
,
accountID
int64
,
params
PaginationParams
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByAccount
(
ctx
context
.
Context
,
accountID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
var
total
int64
...
...
@@ -289,7 +291,7 @@ func (r *UsageLogRepository) ListByAccount(ctx context.Context, accountID int64,
pages
++
}
return
logs
,
&
PaginationResult
{
return
logs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -297,7 +299,7 @@ func (r *UsageLogRepository) ListByAccount(ctx context.Context, accountID int64,
},
nil
}
func
(
r
*
UsageLogRepository
)
ListByUserAndTimeRange
(
ctx
context
.
Context
,
userID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByUserAndTimeRange
(
ctx
context
.
Context
,
userID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
err
:=
r
.
db
.
WithContext
(
ctx
)
.
Where
(
"user_id = ? AND created_at >= ? AND created_at < ?"
,
userID
,
startTime
,
endTime
)
.
...
...
@@ -306,7 +308,7 @@ func (r *UsageLogRepository) ListByUserAndTimeRange(ctx context.Context, userID
return
logs
,
nil
,
err
}
func
(
r
*
UsageLogRepository
)
ListByApiKeyAndTimeRange
(
ctx
context
.
Context
,
apiKeyID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByApiKeyAndTimeRange
(
ctx
context
.
Context
,
apiKeyID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
err
:=
r
.
db
.
WithContext
(
ctx
)
.
Where
(
"api_key_id = ? AND created_at >= ? AND created_at < ?"
,
apiKeyID
,
startTime
,
endTime
)
.
...
...
@@ -315,7 +317,7 @@ func (r *UsageLogRepository) ListByApiKeyAndTimeRange(ctx context.Context, apiKe
return
logs
,
nil
,
err
}
func
(
r
*
UsageLogRepository
)
ListByAccountAndTimeRange
(
ctx
context
.
Context
,
accountID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByAccountAndTimeRange
(
ctx
context
.
Context
,
accountID
int64
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
err
:=
r
.
db
.
WithContext
(
ctx
)
.
Where
(
"account_id = ? AND created_at >= ? AND created_at < ?"
,
accountID
,
startTime
,
endTime
)
.
...
...
@@ -324,7 +326,7 @@ func (r *UsageLogRepository) ListByAccountAndTimeRange(ctx context.Context, acco
return
logs
,
nil
,
err
}
func
(
r
*
UsageLogRepository
)
ListByModelAndTimeRange
(
ctx
context
.
Context
,
modelName
string
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListByModelAndTimeRange
(
ctx
context
.
Context
,
modelName
string
,
startTime
,
endTime
time
.
Time
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
err
:=
r
.
db
.
WithContext
(
ctx
)
.
Where
(
"model = ? AND created_at >= ? AND created_at < ?"
,
modelName
,
startTime
,
endTime
)
.
...
...
@@ -337,15 +339,8 @@ func (r *UsageLogRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
UsageLog
{},
id
)
.
Error
}
// AccountStats 账号使用统计
type
AccountStats
struct
{
Requests
int64
`json:"requests"`
Tokens
int64
`json:"tokens"`
Cost
float64
`json:"cost"`
}
// GetAccountTodayStats 获取账号今日统计
func
(
r
*
UsageLogRepository
)
GetAccountTodayStats
(
ctx
context
.
Context
,
accountID
int64
)
(
*
AccountStats
,
error
)
{
func
(
r
*
UsageLogRepository
)
GetAccountTodayStats
(
ctx
context
.
Context
,
accountID
int64
)
(
*
usagestats
.
AccountStats
,
error
)
{
today
:=
timezone
.
Today
()
var
stats
struct
{
...
...
@@ -367,7 +362,7 @@ func (r *UsageLogRepository) GetAccountTodayStats(ctx context.Context, accountID
return
nil
,
err
}
return
&
AccountStats
{
return
&
usagestats
.
AccountStats
{
Requests
:
stats
.
Requests
,
Tokens
:
stats
.
Tokens
,
Cost
:
stats
.
Cost
,
...
...
@@ -375,7 +370,7 @@ func (r *UsageLogRepository) GetAccountTodayStats(ctx context.Context, accountID
}
// GetAccountWindowStats 获取账号时间窗口内的统计
func
(
r
*
UsageLogRepository
)
GetAccountWindowStats
(
ctx
context
.
Context
,
accountID
int64
,
startTime
time
.
Time
)
(
*
AccountStats
,
error
)
{
func
(
r
*
UsageLogRepository
)
GetAccountWindowStats
(
ctx
context
.
Context
,
accountID
int64
,
startTime
time
.
Time
)
(
*
usagestats
.
AccountStats
,
error
)
{
var
stats
struct
{
Requests
int64
`gorm:"column:requests"`
Tokens
int64
`gorm:"column:tokens"`
...
...
@@ -395,7 +390,7 @@ func (r *UsageLogRepository) GetAccountWindowStats(ctx context.Context, accountI
return
nil
,
err
}
return
&
AccountStats
{
return
&
usagestats
.
AccountStats
{
Requests
:
stats
.
Requests
,
Tokens
:
stats
.
Tokens
,
Cost
:
stats
.
Cost
,
...
...
@@ -500,11 +495,11 @@ func (r *UsageLogRepository) GetModelStats(ctx context.Context, startTime, endTi
// ApiKeyUsageTrendPoint represents API key usage trend data point
type
ApiKeyUsageTrendPoint
struct
{
Date
string
`json:"date"`
ApiKeyID
int64
`json:"api_key_id"`
KeyName
string
`json:"key_name"`
Requests
int64
`json:"requests"`
Tokens
int64
`json:"tokens"`
Date
string
`json:"date"`
ApiKeyID
int64
`json:"api_key_id"`
KeyName
string
`json:"key_name"`
Requests
int64
`json:"requests"`
Tokens
int64
`json:"tokens"`
}
// GetApiKeyUsageTrend returns usage trend data grouped by API key and date
...
...
@@ -780,7 +775,7 @@ type UsageLogFilters struct {
}
// ListWithFilters lists usage logs with optional filters (for admin)
func
(
r
*
UsageLogRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
filters
UsageLogFilters
)
([]
model
.
UsageLog
,
*
PaginationResult
,
error
)
{
func
(
r
*
UsageLogRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
filters
UsageLogFilters
)
([]
model
.
UsageLog
,
*
pagination
.
PaginationResult
,
error
)
{
var
logs
[]
model
.
UsageLog
var
total
int64
...
...
@@ -816,7 +811,7 @@ func (r *UsageLogRepository) ListWithFilters(ctx context.Context, params Paginat
pages
++
}
return
logs
,
&
PaginationResult
{
return
logs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -838,7 +833,7 @@ type UsageStats struct {
// BatchUserUsageStats represents usage stats for a single user
type
BatchUserUsageStats
struct
{
UserID
int64
`json:"user_id"`
UserID
int64
`json:"user_id"`
TodayActualCost
float64
`json:"today_actual_cost"`
TotalActualCost
float64
`json:"total_actual_cost"`
}
...
...
backend/internal/repository/user_repo.go
View file @
e99b344b
...
...
@@ -3,6 +3,7 @@ package repository
import
(
"context"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"gorm.io/gorm"
)
...
...
@@ -45,12 +46,12 @@ func (r *UserRepository) Delete(ctx context.Context, id int64) error {
return
r
.
db
.
WithContext
(
ctx
)
.
Delete
(
&
model
.
User
{},
id
)
.
Error
}
func
(
r
*
UserRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
)
([]
model
.
User
,
*
PaginationResult
,
error
)
{
func
(
r
*
UserRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
User
,
*
pagination
.
PaginationResult
,
error
)
{
return
r
.
ListWithFilters
(
ctx
,
params
,
""
,
""
,
""
)
}
// ListWithFilters lists users with optional filtering by status, role, and search query
func
(
r
*
UserRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
PaginationParams
,
status
,
role
,
search
string
)
([]
model
.
User
,
*
PaginationResult
,
error
)
{
func
(
r
*
UserRepository
)
ListWithFilters
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
status
,
role
,
search
string
)
([]
model
.
User
,
*
pagination
.
PaginationResult
,
error
)
{
var
users
[]
model
.
User
var
total
int64
...
...
@@ -81,7 +82,7 @@ func (r *UserRepository) ListWithFilters(ctx context.Context, params PaginationP
pages
++
}
return
users
,
&
PaginationResult
{
return
users
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -127,4 +128,3 @@ func (r *UserRepository) RemoveGroupFromAllowedGroups(ctx context.Context, group
Update
(
"allowed_groups"
,
gorm
.
Expr
(
"array_remove(allowed_groups, ?)"
,
groupID
))
return
result
.
RowsAffected
,
result
.
Error
}
backend/internal/repository/user_subscription_repo.go
View file @
e99b344b
...
...
@@ -5,6 +5,7 @@ import (
"time"
"sub2api/internal/model"
"sub2api/internal/pkg/pagination"
"gorm.io/gorm"
)
...
...
@@ -100,7 +101,7 @@ func (r *UserSubscriptionRepository) ListActiveByUserID(ctx context.Context, use
}
// ListByGroupID 获取分组的所有订阅(分页)
func
(
r
*
UserSubscriptionRepository
)
ListByGroupID
(
ctx
context
.
Context
,
groupID
int64
,
params
PaginationParams
)
([]
model
.
UserSubscription
,
*
PaginationResult
,
error
)
{
func
(
r
*
UserSubscriptionRepository
)
ListByGroupID
(
ctx
context
.
Context
,
groupID
int64
,
params
pagination
.
PaginationParams
)
([]
model
.
UserSubscription
,
*
pagination
.
PaginationResult
,
error
)
{
var
subs
[]
model
.
UserSubscription
var
total
int64
...
...
@@ -126,7 +127,7 @@ func (r *UserSubscriptionRepository) ListByGroupID(ctx context.Context, groupID
pages
++
}
return
subs
,
&
PaginationResult
{
return
subs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
@@ -135,7 +136,7 @@ func (r *UserSubscriptionRepository) ListByGroupID(ctx context.Context, groupID
}
// List 获取所有订阅(分页,支持筛选)
func
(
r
*
UserSubscriptionRepository
)
List
(
ctx
context
.
Context
,
params
PaginationParams
,
userID
,
groupID
*
int64
,
status
string
)
([]
model
.
UserSubscription
,
*
PaginationResult
,
error
)
{
func
(
r
*
UserSubscriptionRepository
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
,
userID
,
groupID
*
int64
,
status
string
)
([]
model
.
UserSubscription
,
*
pagination
.
PaginationResult
,
error
)
{
var
subs
[]
model
.
UserSubscription
var
total
int64
...
...
@@ -172,7 +173,7 @@ func (r *UserSubscriptionRepository) List(ctx context.Context, params Pagination
pages
++
}
return
subs
,
&
PaginationResult
{
return
subs
,
&
pagination
.
PaginationResult
{
Total
:
total
,
Page
:
params
.
Page
,
PageSize
:
params
.
Limit
(),
...
...
backend/internal/repository/wire.go
View file @
e99b344b
package
repository
import
(
"sub2api/internal/service/ports"
"github.com/google/wire"
)
...
...
@@ -16,4 +18,15 @@ var ProviderSet = wire.NewSet(
NewSettingRepository
,
NewUserSubscriptionRepository
,
wire
.
Struct
(
new
(
Repositories
),
"*"
),
// Bind concrete repositories to service port interfaces
wire
.
Bind
(
new
(
ports
.
UserRepository
),
new
(
*
UserRepository
)),
wire
.
Bind
(
new
(
ports
.
ApiKeyRepository
),
new
(
*
ApiKeyRepository
)),
wire
.
Bind
(
new
(
ports
.
GroupRepository
),
new
(
*
GroupRepository
)),
wire
.
Bind
(
new
(
ports
.
AccountRepository
),
new
(
*
AccountRepository
)),
wire
.
Bind
(
new
(
ports
.
ProxyRepository
),
new
(
*
ProxyRepository
)),
wire
.
Bind
(
new
(
ports
.
RedeemCodeRepository
),
new
(
*
RedeemCodeRepository
)),
wire
.
Bind
(
new
(
ports
.
UsageLogRepository
),
new
(
*
UsageLogRepository
)),
wire
.
Bind
(
new
(
ports
.
SettingRepository
),
new
(
*
SettingRepository
)),
wire
.
Bind
(
new
(
ports
.
UserSubscriptionRepository
),
new
(
*
UserSubscriptionRepository
)),
)
backend/internal/service/account_service.go
View file @
e99b344b
...
...
@@ -5,7 +5,8 @@ import (
"errors"
"fmt"
"sub2api/internal/model"
"sub2api/internal/repository"
"sub2api/internal/pkg/pagination"
"sub2api/internal/service/ports"
"gorm.io/gorm"
)
...
...
@@ -41,12 +42,12 @@ type UpdateAccountRequest struct {
// AccountService 账号管理服务
type
AccountService
struct
{
accountRepo
*
repository
.
AccountRepository
groupRepo
*
repository
.
GroupRepository
accountRepo
ports
.
AccountRepository
groupRepo
ports
.
GroupRepository
}
// NewAccountService 创建账号服务实例
func
NewAccountService
(
accountRepo
*
repository
.
AccountRepository
,
groupRepo
*
repository
.
GroupRepository
)
*
AccountService
{
func
NewAccountService
(
accountRepo
ports
.
AccountRepository
,
groupRepo
ports
.
GroupRepository
)
*
AccountService
{
return
&
AccountService
{
accountRepo
:
accountRepo
,
groupRepo
:
groupRepo
,
...
...
@@ -108,7 +109,7 @@ func (s *AccountService) GetByID(ctx context.Context, id int64) (*model.Account,
}
// List 获取账号列表
func
(
s
*
AccountService
)
List
(
ctx
context
.
Context
,
params
repository
.
PaginationParams
)
([]
model
.
Account
,
*
repository
.
PaginationResult
,
error
)
{
func
(
s
*
AccountService
)
List
(
ctx
context
.
Context
,
params
pagination
.
PaginationParams
)
([]
model
.
Account
,
*
pagination
.
PaginationResult
,
error
)
{
accounts
,
pagination
,
err
:=
s
.
accountRepo
.
List
(
ctx
,
params
)
if
err
!=
nil
{
return
nil
,
nil
,
fmt
.
Errorf
(
"list accounts: %w"
,
err
)
...
...
backend/internal/service/account_test_service.go
View file @
e99b344b
...
...
@@ -16,7 +16,7 @@ import (
"time"
"sub2api/internal/pkg/claude"
"sub2api/internal/
repository
"
"sub2api/internal/
service/ports
"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
...
...
@@ -37,15 +37,15 @@ type TestEvent struct {
// AccountTestService handles account testing operations
type
AccountTestService
struct
{
r
epo
s
*
repository
.
Repositor
ies
accountR
epo
ports
.
Account
Repositor
y
oauthService
*
OAuthService
httpClient
*
http
.
Client
}
// NewAccountTestService creates a new AccountTestService
func
NewAccountTestService
(
repos
*
repository
.
Repositor
ies
,
oauthService
*
OAuthService
)
*
AccountTestService
{
func
NewAccountTestService
(
accountRepo
ports
.
Account
Repositor
y
,
oauthService
*
OAuthService
)
*
AccountTestService
{
return
&
AccountTestService
{
r
epo
s
:
r
epo
s
,
accountR
epo
:
accountR
epo
,
oauthService
:
oauthService
,
httpClient
:
&
http
.
Client
{
Timeout
:
60
*
time
.
Second
,
...
...
@@ -105,7 +105,7 @@ func (s *AccountTestService) TestAccountConnection(c *gin.Context, accountID int
ctx
:=
c
.
Request
.
Context
()
// Get account
account
,
err
:=
s
.
repos
.
A
ccount
.
GetByID
(
ctx
,
accountID
)
account
,
err
:=
s
.
a
ccount
Repo
.
GetByID
(
ctx
,
accountID
)
if
err
!=
nil
{
return
s
.
sendErrorAndEnd
(
c
,
"Account not found"
)
}
...
...
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment