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
295d71be
"backend/internal/pkg/vscode:/vscode.git/clone" did not exist on "ff8b1b4ae33e32397b669cb19ca05d7925fa852f"
Unverified
Commit
295d71be
authored
Dec 28, 2025
by
程序猿MT
Committed by
GitHub
Dec 28, 2025
Browse files
Merge branch 'Wei-Shaw:main' into main
parents
1d1da736
9bbe468c
Changes
20
Show whitespace changes
Inline
Side-by-side
.gitignore
View file @
295d71be
...
@@ -32,6 +32,7 @@ frontend/node_modules/
...
@@ -32,6 +32,7 @@ frontend/node_modules/
frontend/dist/
frontend/dist/
*.local
*.local
*.tsbuildinfo
*.tsbuildinfo
vite.config.d.ts
# 日志
# 日志
npm-debug.log*
npm-debug.log*
...
...
backend/cmd/server/wire_gen.go
View file @
295d71be
...
@@ -117,10 +117,12 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -117,10 +117,12 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
billingService
:=
service
.
NewBillingService
(
configConfig
,
pricingService
)
billingService
:=
service
.
NewBillingService
(
configConfig
,
pricingService
)
identityCache
:=
repository
.
NewIdentityCache
(
client
)
identityCache
:=
repository
.
NewIdentityCache
(
client
)
identityService
:=
service
.
NewIdentityService
(
identityCache
)
identityService
:=
service
.
NewIdentityService
(
identityCache
)
gatewayService
:=
service
.
NewGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
,
httpUpstream
)
timingWheelService
:=
service
.
ProvideTimingWheelService
()
deferredService
:=
service
.
ProvideDeferredService
(
accountRepository
,
timingWheelService
)
gatewayService
:=
service
.
NewGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
,
httpUpstream
,
deferredService
)
geminiMessagesCompatService
:=
service
.
NewGeminiMessagesCompatService
(
accountRepository
,
gatewayCache
,
geminiTokenProvider
,
rateLimitService
,
httpUpstream
)
geminiMessagesCompatService
:=
service
.
NewGeminiMessagesCompatService
(
accountRepository
,
gatewayCache
,
geminiTokenProvider
,
rateLimitService
,
httpUpstream
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
userService
,
concurrencyService
,
billingCacheService
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
userService
,
concurrencyService
,
billingCacheService
)
openAIGatewayService
:=
service
.
NewOpenAIGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
billingService
,
rateLimitService
,
billingCacheService
,
httpUpstream
)
openAIGatewayService
:=
service
.
NewOpenAIGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
billingService
,
rateLimitService
,
billingCacheService
,
httpUpstream
,
deferredService
)
openAIGatewayHandler
:=
handler
.
NewOpenAIGatewayHandler
(
openAIGatewayService
,
concurrencyService
,
billingCacheService
)
openAIGatewayHandler
:=
handler
.
NewOpenAIGatewayHandler
(
openAIGatewayService
,
concurrencyService
,
billingCacheService
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
handlers
:=
handler
.
ProvideHandlers
(
authHandler
,
userHandler
,
apiKeyHandler
,
usageHandler
,
redeemHandler
,
subscriptionHandler
,
adminHandlers
,
gatewayHandler
,
openAIGatewayHandler
,
handlerSettingHandler
)
handlers
:=
handler
.
ProvideHandlers
(
authHandler
,
userHandler
,
apiKeyHandler
,
usageHandler
,
redeemHandler
,
subscriptionHandler
,
adminHandlers
,
gatewayHandler
,
openAIGatewayHandler
,
handlerSettingHandler
)
...
...
backend/go.mod
View file @
295d71be
...
@@ -11,13 +11,14 @@ require (
...
@@ -11,13 +11,14 @@ require (
github.com/google/wire v0.7.0
github.com/google/wire v0.7.0
github.com/imroc/req/v3 v3.56.0
github.com/imroc/req/v3 v3.56.0
github.com/lib/pq v1.10.9
github.com/lib/pq v1.10.9
github.com/redis/go-redis/v9 v9.7.
3
github.com/redis/go-redis/v9 v9.
1
7.
2
github.com/spf13/viper v1.18.2
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.11.1
github.com/stretchr/testify v1.11.1
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0
github.com/testcontainers/testcontainers-go/modules/postgres v0.40.0
github.com/testcontainers/testcontainers-go/modules/redis v0.40.0
github.com/testcontainers/testcontainers-go/modules/redis v0.40.0
github.com/tidwall/gjson v1.18.0
github.com/tidwall/gjson v1.18.0
github.com/tidwall/sjson v1.2.5
github.com/tidwall/sjson v1.2.5
github.com/zeromicro/go-zero v1.9.4
golang.org/x/crypto v0.44.0
golang.org/x/crypto v0.44.0
golang.org/x/net v0.47.0
golang.org/x/net v0.47.0
golang.org/x/term v0.37.0
golang.org/x/term v0.37.0
...
@@ -49,6 +50,7 @@ require (
...
@@ -49,6 +50,7 @@ require (
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
...
@@ -59,7 +61,7 @@ require (
...
@@ -59,7 +61,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/go-sql-driver/mysql v1.
8.1
// indirect
github.com/go-sql-driver/mysql v1.
9.0
// indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/google/subcommands v1.2.0 // indirect
...
@@ -67,9 +69,9 @@ require (
...
@@ -67,9 +69,9 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/icholy/digest v1.1.0 // indirect
github.com/icholy/digest v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-202
3120
12
3
52
50-de7065d80cb9
// indirect
github.com/jackc/pgservicefile v0.0.0-202
40606
12
0
52
3-5a60cdf6a761
// indirect
github.com/jackc/pgx/v5 v5.
5.5
// indirect
github.com/jackc/pgx/v5 v5.
7.4
// indirect
github.com/jackc/puddle/v2 v2.2.
1
// indirect
github.com/jackc/puddle/v2 v2.2.
2
// indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/json-iterator/go v1.1.12 // indirect
...
@@ -78,7 +80,8 @@ require (
...
@@ -78,7 +80,8 @@ require (
github.com/leodido/go-urn v1.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mdelapenya/tlscert v0.2.0 // indirect
github.com/mdelapenya/tlscert v0.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
...
@@ -93,7 +96,7 @@ require (
...
@@ -93,7 +96,7 @@ require (
github.com/morikuni/aec v1.0.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.
1.0
// indirect
github.com/pelletier/go-toml/v2 v2.
2.2
// indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
...
@@ -105,6 +108,7 @@ require (
...
@@ -105,6 +108,7 @@ require (
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
...
@@ -123,7 +127,8 @@ require (
...
@@ -123,7 +127,8 @@ require (
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
...
...
backend/go.sum
View file @
295d71be
...
@@ -52,6 +52,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
...
@@ -52,6 +52,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
...
@@ -80,8 +82,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
...
@@ -80,8 +82,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.
8.1
h1:
LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y
=
github.com/go-sql-driver/mysql v1.
9.0
h1:
Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo
=
github.com/go-sql-driver/mysql v1.
8.1
/go.mod h1:
wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg
=
github.com/go-sql-driver/mysql v1.
9.0
/go.mod h1:
pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw
=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
...
@@ -113,12 +115,12 @@ github.com/imroc/req/v3 v3.56.0 h1:t6YdqqerYBXhZ9+VjqsQs5wlKxdUNEvsgBhxWc1AEEo=
...
@@ -113,12 +115,12 @@ github.com/imroc/req/v3 v3.56.0 h1:t6YdqqerYBXhZ9+VjqsQs5wlKxdUNEvsgBhxWc1AEEo=
github.com/imroc/req/v3 v3.56.0/go.mod h1:cUZSooE8hhzFNOrAbdxuemXDQxFXLQTnu3066jr7ZGk=
github.com/imroc/req/v3 v3.56.0/go.mod h1:cUZSooE8hhzFNOrAbdxuemXDQxFXLQTnu3066jr7ZGk=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-202
3
120
1
23
5250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA
=
github.com/jackc/pgservicefile v0.0.0-202
40606
120
5
23
-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo
=
github.com/jackc/pgservicefile v0.0.0-202
3120
12
3
52
50-de7065d80cb9
/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgservicefile v0.0.0-202
40606
12
0
52
3-5a60cdf6a761
/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.
5.5
h1:
amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw
=
github.com/jackc/pgx/v5 v5.
7.4
h1:
9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg
=
github.com/jackc/pgx/v5 v5.
5.5
/go.mod h1:
ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A
=
github.com/jackc/pgx/v5 v5.
7.4
/go.mod h1:
ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ
=
github.com/jackc/puddle/v2 v2.2.
1
h1:
RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk
=
github.com/jackc/puddle/v2 v2.2.
2
h1:
PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
=
github.com/jackc/puddle/v2 v2.2.
1
/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/puddle/v2 v2.2.
2
/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
...
@@ -142,8 +144,11 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
...
@@ -142,8 +144,11 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI=
github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI=
...
@@ -179,8 +184,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
...
@@ -179,8 +184,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pelletier/go-toml/v2 v2.
1.0
h1:
FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4
=
github.com/pelletier/go-toml/v2 v2.
2.2
h1:
aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM
=
github.com/pelletier/go-toml/v2 v2.
1.0
/go.mod h1:
tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc
=
github.com/pelletier/go-toml/v2 v2.
2.2
/go.mod h1:
1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs
=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
...
@@ -188,12 +193,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
...
@@ -188,12 +193,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY=
github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY=
github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c=
github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c=
github.com/redis/go-redis/v9 v9.7.
3
h1:
YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM
=
github.com/redis/go-redis/v9 v9.
1
7.
2
h1:
P2EGsA4qVIM3Pp+aPocCJ7DguDHhqrXNhVcEp4ViluI
=
github.com/redis/go-redis/v9 v9.7.
3
/go.mod h1:
bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA
=
github.com/redis/go-redis/v9 v9.
1
7.
2
/go.mod h1:
u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370
=
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
...
@@ -208,6 +215,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
...
@@ -208,6 +215,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
...
@@ -228,6 +237,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
...
@@ -228,6 +237,7 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
...
@@ -259,26 +269,30 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
...
@@ -259,26 +269,30 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zeromicro/go-zero v1.9.4 h1:aRLFoISqAYijABtkbliQC5SsI5TbizJpQvoHc9xup8k=
github.com/zeromicro/go-zero v1.9.4/go.mod h1:a17JOTch25SWxBcUgJZYps60hygK3pIYdw7nGwlcS38=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.
19
.0 h1:
Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.
24
.0 h1:
t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.
19
.0/go.mod h1:
IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.
24
.0/go.mod h1:
iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.
19
.0 h1:
IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.
24
.0 h1:
Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.
19
.0/go.mod h1:
oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU
=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.
24
.0/go.mod h1:
6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM
=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
...
@@ -301,6 +315,7 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
...
@@ -301,6 +315,7 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
...
...
backend/internal/handler/admin/redeem_handler.go
View file @
295d71be
...
@@ -31,7 +31,7 @@ type GenerateRedeemCodesRequest struct {
...
@@ -31,7 +31,7 @@ type GenerateRedeemCodesRequest struct {
Type
string
`json:"type" binding:"required,oneof=balance concurrency subscription"`
Type
string
`json:"type" binding:"required,oneof=balance concurrency subscription"`
Value
float64
`json:"value" binding:"min=0"`
Value
float64
`json:"value" binding:"min=0"`
GroupID
*
int64
`json:"group_id"`
// 订阅类型必填
GroupID
*
int64
`json:"group_id"`
// 订阅类型必填
ValidityDays
int
`json:"validity_days"`
// 订阅类型使用,默认30天
ValidityDays
int
`json:"validity_days"
binding:"omitempty,max=36500"
`
// 订阅类型使用,默认30天
,最大100年
}
}
// List handles listing all redeem codes with pagination
// List handles listing all redeem codes with pagination
...
...
backend/internal/handler/admin/subscription_handler.go
View file @
295d71be
...
@@ -41,7 +41,7 @@ func NewSubscriptionHandler(subscriptionService *service.SubscriptionService) *S
...
@@ -41,7 +41,7 @@ func NewSubscriptionHandler(subscriptionService *service.SubscriptionService) *S
type
AssignSubscriptionRequest
struct
{
type
AssignSubscriptionRequest
struct
{
UserID
int64
`json:"user_id" binding:"required"`
UserID
int64
`json:"user_id" binding:"required"`
GroupID
int64
`json:"group_id" binding:"required"`
GroupID
int64
`json:"group_id" binding:"required"`
ValidityDays
int
`json:"validity_days"
`
ValidityDays
int
`json:"validity_days"
binding:"omitempty,max=36500"`
// max 100 years
Notes
string
`json:"notes"`
Notes
string
`json:"notes"`
}
}
...
@@ -49,13 +49,13 @@ type AssignSubscriptionRequest struct {
...
@@ -49,13 +49,13 @@ type AssignSubscriptionRequest struct {
type
BulkAssignSubscriptionRequest
struct
{
type
BulkAssignSubscriptionRequest
struct
{
UserIDs
[]
int64
`json:"user_ids" binding:"required,min=1"`
UserIDs
[]
int64
`json:"user_ids" binding:"required,min=1"`
GroupID
int64
`json:"group_id" binding:"required"`
GroupID
int64
`json:"group_id" binding:"required"`
ValidityDays
int
`json:"validity_days"
`
ValidityDays
int
`json:"validity_days"
binding:"omitempty,max=36500"`
// max 100 years
Notes
string
`json:"notes"`
Notes
string
`json:"notes"`
}
}
// ExtendSubscriptionRequest represents extend subscription request
// ExtendSubscriptionRequest represents extend subscription request
type
ExtendSubscriptionRequest
struct
{
type
ExtendSubscriptionRequest
struct
{
Days
int
`json:"days" binding:"required,min=1
"`
Days
int
`json:"days" binding:"required,min=1
,max=36500"`
// max 100 years
}
}
// List handles listing all subscriptions with pagination and filters
// List handles listing all subscriptions with pagination and filters
...
...
backend/internal/repository/account_repo.go
View file @
295d71be
...
@@ -171,6 +171,27 @@ func (r *accountRepository) UpdateLastUsed(ctx context.Context, id int64) error
...
@@ -171,6 +171,27 @@ func (r *accountRepository) UpdateLastUsed(ctx context.Context, id int64) error
return
r
.
db
.
WithContext
(
ctx
)
.
Model
(
&
accountModel
{})
.
Where
(
"id = ?"
,
id
)
.
Update
(
"last_used_at"
,
now
)
.
Error
return
r
.
db
.
WithContext
(
ctx
)
.
Model
(
&
accountModel
{})
.
Where
(
"id = ?"
,
id
)
.
Update
(
"last_used_at"
,
now
)
.
Error
}
}
func
(
r
*
accountRepository
)
BatchUpdateLastUsed
(
ctx
context
.
Context
,
updates
map
[
int64
]
time
.
Time
)
error
{
if
len
(
updates
)
==
0
{
return
nil
}
var
caseSql
=
"UPDATE accounts SET last_used_at = CASE id"
var
args
[]
any
var
ids
[]
int64
for
id
,
ts
:=
range
updates
{
caseSql
+=
" WHEN ? THEN CAST(? AS TIMESTAMP)"
args
=
append
(
args
,
id
,
ts
)
ids
=
append
(
ids
,
id
)
}
caseSql
+=
" END WHERE id IN ?"
args
=
append
(
args
,
ids
)
return
r
.
db
.
WithContext
(
ctx
)
.
Exec
(
caseSql
,
args
...
)
.
Error
}
func
(
r
*
accountRepository
)
SetError
(
ctx
context
.
Context
,
id
int64
,
errorMsg
string
)
error
{
func
(
r
*
accountRepository
)
SetError
(
ctx
context
.
Context
,
id
int64
,
errorMsg
string
)
error
{
return
r
.
db
.
WithContext
(
ctx
)
.
Model
(
&
accountModel
{})
.
Where
(
"id = ?"
,
id
)
.
return
r
.
db
.
WithContext
(
ctx
)
.
Model
(
&
accountModel
{})
.
Where
(
"id = ?"
,
id
)
.
Updates
(
map
[
string
]
any
{
Updates
(
map
[
string
]
any
{
...
...
backend/internal/repository/auto_migrate.go
View file @
295d71be
package
repository
package
repository
import
"gorm.io/gorm"
import
(
"log"
"time"
"gorm.io/gorm"
)
// MaxExpiresAt is the maximum allowed expiration date for subscriptions (year 2099)
// This prevents time.Time JSON serialization errors (RFC 3339 requires year <= 9999)
var
maxExpiresAt
=
time
.
Date
(
2099
,
12
,
31
,
23
,
59
,
59
,
0
,
time
.
UTC
)
// AutoMigrate runs schema migrations for all repository persistence models.
// AutoMigrate runs schema migrations for all repository persistence models.
// Persistence models are defined within individual `*_repo.go` files.
// Persistence models are defined within individual `*_repo.go` files.
func
AutoMigrate
(
db
*
gorm
.
DB
)
error
{
func
AutoMigrate
(
db
*
gorm
.
DB
)
error
{
return
db
.
AutoMigrate
(
err
:=
db
.
AutoMigrate
(
&
userModel
{},
&
userModel
{},
&
apiKeyModel
{},
&
apiKeyModel
{},
&
groupModel
{},
&
groupModel
{},
...
@@ -17,4 +26,24 @@ func AutoMigrate(db *gorm.DB) error {
...
@@ -17,4 +26,24 @@ func AutoMigrate(db *gorm.DB) error {
&
settingModel
{},
&
settingModel
{},
&
userSubscriptionModel
{},
&
userSubscriptionModel
{},
)
)
if
err
!=
nil
{
return
err
}
// 修复无效的过期时间(年份超过 2099 会导致 JSON 序列化失败)
return
fixInvalidExpiresAt
(
db
)
}
// fixInvalidExpiresAt 修复 user_subscriptions 表中无效的过期时间
func
fixInvalidExpiresAt
(
db
*
gorm
.
DB
)
error
{
result
:=
db
.
Model
(
&
userSubscriptionModel
{})
.
Where
(
"expires_at > ?"
,
maxExpiresAt
)
.
Update
(
"expires_at"
,
maxExpiresAt
)
if
result
.
Error
!=
nil
{
return
result
.
Error
}
if
result
.
RowsAffected
>
0
{
log
.
Printf
(
"[AutoMigrate] Fixed %d subscriptions with invalid expires_at (year > 2099)"
,
result
.
RowsAffected
)
}
return
nil
}
}
backend/internal/service/account.go
View file @
295d71be
package
service
package
service
import
(
import
(
"encoding/json"
"strconv"
"strconv"
"time"
"time"
)
)
...
@@ -94,6 +95,9 @@ func (a *Account) GetCredential(key string) string {
...
@@ -94,6 +95,9 @@ func (a *Account) GetCredential(key string) string {
switch
val
:=
v
.
(
type
)
{
switch
val
:=
v
.
(
type
)
{
case
string
:
case
string
:
return
val
return
val
case
json
.
Number
:
// GORM datatypes.JSONMap 使用 UseNumber() 解析,数字类型为 json.Number
return
val
.
String
()
case
float64
:
case
float64
:
// JSON 解析后数字默认为 float64
// JSON 解析后数字默认为 float64
return
strconv
.
FormatInt
(
int64
(
val
),
10
)
return
strconv
.
FormatInt
(
int64
(
val
),
10
)
...
...
backend/internal/service/account_service.go
View file @
295d71be
...
@@ -29,6 +29,7 @@ type AccountRepository interface {
...
@@ -29,6 +29,7 @@ type AccountRepository interface {
ListByPlatform
(
ctx
context
.
Context
,
platform
string
)
([]
Account
,
error
)
ListByPlatform
(
ctx
context
.
Context
,
platform
string
)
([]
Account
,
error
)
UpdateLastUsed
(
ctx
context
.
Context
,
id
int64
)
error
UpdateLastUsed
(
ctx
context
.
Context
,
id
int64
)
error
BatchUpdateLastUsed
(
ctx
context
.
Context
,
updates
map
[
int64
]
time
.
Time
)
error
SetError
(
ctx
context
.
Context
,
id
int64
,
errorMsg
string
)
error
SetError
(
ctx
context
.
Context
,
id
int64
,
errorMsg
string
)
error
SetSchedulable
(
ctx
context
.
Context
,
id
int64
,
schedulable
bool
)
error
SetSchedulable
(
ctx
context
.
Context
,
id
int64
,
schedulable
bool
)
error
BindGroups
(
ctx
context
.
Context
,
accountID
int64
,
groupIDs
[]
int64
)
error
BindGroups
(
ctx
context
.
Context
,
accountID
int64
,
groupIDs
[]
int64
)
error
...
...
backend/internal/service/deferred_service.go
0 → 100644
View file @
295d71be
package
service
import
(
"context"
"log"
"sync"
"time"
)
// DeferredService provides deferred batch update functionality
type
DeferredService
struct
{
accountRepo
AccountRepository
timingWheel
*
TimingWheelService
interval
time
.
Duration
lastUsedUpdates
sync
.
Map
}
// NewDeferredService creates a new DeferredService instance
func
NewDeferredService
(
accountRepo
AccountRepository
,
timingWheel
*
TimingWheelService
,
interval
time
.
Duration
)
*
DeferredService
{
return
&
DeferredService
{
accountRepo
:
accountRepo
,
timingWheel
:
timingWheel
,
interval
:
interval
,
}
}
// Start starts the deferred service
func
(
s
*
DeferredService
)
Start
()
{
s
.
timingWheel
.
ScheduleRecurring
(
"deferred:last_used"
,
s
.
interval
,
s
.
flushLastUsed
)
log
.
Printf
(
"[DeferredService] Started (interval: %v)"
,
s
.
interval
)
}
// Stop stops the deferred service
func
(
s
*
DeferredService
)
Stop
()
{
s
.
timingWheel
.
Cancel
(
"deferred:last_used"
)
s
.
flushLastUsed
()
log
.
Printf
(
"[DeferredService] Service stopped"
)
}
func
(
s
*
DeferredService
)
ScheduleLastUsedUpdate
(
accountID
int64
)
{
s
.
lastUsedUpdates
.
Store
(
accountID
,
time
.
Now
())
}
func
(
s
*
DeferredService
)
flushLastUsed
()
{
updates
:=
make
(
map
[
int64
]
time
.
Time
)
s
.
lastUsedUpdates
.
Range
(
func
(
key
,
value
any
)
bool
{
id
,
ok
:=
key
.
(
int64
)
if
!
ok
{
return
true
}
ts
,
ok
:=
value
.
(
time
.
Time
)
if
!
ok
{
return
true
}
updates
[
id
]
=
ts
s
.
lastUsedUpdates
.
Delete
(
key
)
return
true
})
if
len
(
updates
)
==
0
{
return
}
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
if
err
:=
s
.
accountRepo
.
BatchUpdateLastUsed
(
ctx
,
updates
);
err
!=
nil
{
log
.
Printf
(
"[DeferredService] BatchUpdateLastUsed failed (%d accounts): %v"
,
len
(
updates
),
err
)
for
id
,
ts
:=
range
updates
{
s
.
lastUsedUpdates
.
Store
(
id
,
ts
)
}
}
else
{
log
.
Printf
(
"[DeferredService] BatchUpdateLastUsed flushed %d accounts"
,
len
(
updates
))
}
}
backend/internal/service/gateway_service.go
View file @
295d71be
...
@@ -103,6 +103,7 @@ type GatewayService struct {
...
@@ -103,6 +103,7 @@ type GatewayService struct {
billingCacheService
*
BillingCacheService
billingCacheService
*
BillingCacheService
identityService
*
IdentityService
identityService
*
IdentityService
httpUpstream
HTTPUpstream
httpUpstream
HTTPUpstream
deferredService
*
DeferredService
}
}
// NewGatewayService creates a new GatewayService
// NewGatewayService creates a new GatewayService
...
@@ -118,6 +119,7 @@ func NewGatewayService(
...
@@ -118,6 +119,7 @@ func NewGatewayService(
billingCacheService
*
BillingCacheService
,
billingCacheService
*
BillingCacheService
,
identityService
*
IdentityService
,
identityService
*
IdentityService
,
httpUpstream
HTTPUpstream
,
httpUpstream
HTTPUpstream
,
deferredService
*
DeferredService
,
)
*
GatewayService
{
)
*
GatewayService
{
return
&
GatewayService
{
return
&
GatewayService
{
accountRepo
:
accountRepo
,
accountRepo
:
accountRepo
,
...
@@ -131,6 +133,7 @@ func NewGatewayService(
...
@@ -131,6 +133,7 @@ func NewGatewayService(
billingCacheService
:
billingCacheService
,
billingCacheService
:
billingCacheService
,
identityService
:
identityService
,
identityService
:
identityService
,
httpUpstream
:
httpUpstream
,
httpUpstream
:
httpUpstream
,
deferredService
:
deferredService
,
}
}
}
}
...
@@ -1095,10 +1098,8 @@ func (s *GatewayService) RecordUsage(ctx context.Context, input *RecordUsageInpu
...
@@ -1095,10 +1098,8 @@ func (s *GatewayService) RecordUsage(ctx context.Context, input *RecordUsageInpu
}
}
}
}
// 更新账号最后使用时间
// Schedule batch update for account last_used_at
if
err
:=
s
.
accountRepo
.
UpdateLastUsed
(
ctx
,
account
.
ID
);
err
!=
nil
{
s
.
deferredService
.
ScheduleLastUsedUpdate
(
account
.
ID
)
log
.
Printf
(
"Update last used failed: %v"
,
err
)
}
return
nil
return
nil
}
}
...
...
backend/internal/service/openai_gateway_service.go
View file @
295d71be
...
@@ -83,6 +83,7 @@ type OpenAIGatewayService struct {
...
@@ -83,6 +83,7 @@ type OpenAIGatewayService struct {
rateLimitService
*
RateLimitService
rateLimitService
*
RateLimitService
billingCacheService
*
BillingCacheService
billingCacheService
*
BillingCacheService
httpUpstream
HTTPUpstream
httpUpstream
HTTPUpstream
deferredService
*
DeferredService
}
}
// NewOpenAIGatewayService creates a new OpenAIGatewayService
// NewOpenAIGatewayService creates a new OpenAIGatewayService
...
@@ -97,6 +98,7 @@ func NewOpenAIGatewayService(
...
@@ -97,6 +98,7 @@ func NewOpenAIGatewayService(
rateLimitService
*
RateLimitService
,
rateLimitService
*
RateLimitService
,
billingCacheService
*
BillingCacheService
,
billingCacheService
*
BillingCacheService
,
httpUpstream
HTTPUpstream
,
httpUpstream
HTTPUpstream
,
deferredService
*
DeferredService
,
)
*
OpenAIGatewayService
{
)
*
OpenAIGatewayService
{
return
&
OpenAIGatewayService
{
return
&
OpenAIGatewayService
{
accountRepo
:
accountRepo
,
accountRepo
:
accountRepo
,
...
@@ -109,6 +111,7 @@ func NewOpenAIGatewayService(
...
@@ -109,6 +111,7 @@ func NewOpenAIGatewayService(
rateLimitService
:
rateLimitService
,
rateLimitService
:
rateLimitService
,
billingCacheService
:
billingCacheService
,
billingCacheService
:
billingCacheService
,
httpUpstream
:
httpUpstream
,
httpUpstream
:
httpUpstream
,
deferredService
:
deferredService
,
}
}
}
}
...
@@ -772,8 +775,8 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
...
@@ -772,8 +775,8 @@ func (s *OpenAIGatewayService) RecordUsage(ctx context.Context, input *OpenAIRec
}
}
}
}
//
U
pdate account last
used
//
Schedule batch u
pdate
for
account last
_
used
_at
_
=
s
.
accountRepo
.
Updat
eLastUsed
(
ctx
,
account
.
ID
)
s
.
deferredService
.
Schedul
eLastUsed
Update
(
account
.
ID
)
return
nil
return
nil
}
}
...
...
backend/internal/service/subscription_service.go
View file @
295d71be
...
@@ -10,6 +10,13 @@ import (
...
@@ -10,6 +10,13 @@ import (
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
)
)
// MaxExpiresAt is the maximum allowed expiration date (year 2099)
// This prevents time.Time JSON serialization errors (RFC 3339 requires year <= 9999)
var
MaxExpiresAt
=
time
.
Date
(
2099
,
12
,
31
,
23
,
59
,
59
,
0
,
time
.
UTC
)
// MaxValidityDays is the maximum allowed validity days for subscriptions (100 years)
const
MaxValidityDays
=
36500
var
(
var
(
ErrSubscriptionNotFound
=
infraerrors
.
NotFound
(
"SUBSCRIPTION_NOT_FOUND"
,
"subscription not found"
)
ErrSubscriptionNotFound
=
infraerrors
.
NotFound
(
"SUBSCRIPTION_NOT_FOUND"
,
"subscription not found"
)
ErrSubscriptionExpired
=
infraerrors
.
Forbidden
(
"SUBSCRIPTION_EXPIRED"
,
"subscription has expired"
)
ErrSubscriptionExpired
=
infraerrors
.
Forbidden
(
"SUBSCRIPTION_EXPIRED"
,
"subscription has expired"
)
...
@@ -111,6 +118,9 @@ func (s *SubscriptionService) AssignOrExtendSubscription(ctx context.Context, in
...
@@ -111,6 +118,9 @@ func (s *SubscriptionService) AssignOrExtendSubscription(ctx context.Context, in
if
validityDays
<=
0
{
if
validityDays
<=
0
{
validityDays
=
30
validityDays
=
30
}
}
if
validityDays
>
MaxValidityDays
{
validityDays
=
MaxValidityDays
}
// 已有订阅,执行续期
// 已有订阅,执行续期
if
existingSub
!=
nil
{
if
existingSub
!=
nil
{
...
@@ -125,6 +135,11 @@ func (s *SubscriptionService) AssignOrExtendSubscription(ctx context.Context, in
...
@@ -125,6 +135,11 @@ func (s *SubscriptionService) AssignOrExtendSubscription(ctx context.Context, in
newExpiresAt
=
now
.
AddDate
(
0
,
0
,
validityDays
)
newExpiresAt
=
now
.
AddDate
(
0
,
0
,
validityDays
)
}
}
// 确保不超过最大过期时间
if
newExpiresAt
.
After
(
MaxExpiresAt
)
{
newExpiresAt
=
MaxExpiresAt
}
// 更新过期时间
// 更新过期时间
if
err
:=
s
.
userSubRepo
.
ExtendExpiry
(
ctx
,
existingSub
.
ID
,
newExpiresAt
);
err
!=
nil
{
if
err
:=
s
.
userSubRepo
.
ExtendExpiry
(
ctx
,
existingSub
.
ID
,
newExpiresAt
);
err
!=
nil
{
return
nil
,
false
,
fmt
.
Errorf
(
"extend subscription: %w"
,
err
)
return
nil
,
false
,
fmt
.
Errorf
(
"extend subscription: %w"
,
err
)
...
@@ -189,13 +204,21 @@ func (s *SubscriptionService) createSubscription(ctx context.Context, input *Ass
...
@@ -189,13 +204,21 @@ func (s *SubscriptionService) createSubscription(ctx context.Context, input *Ass
if
validityDays
<=
0
{
if
validityDays
<=
0
{
validityDays
=
30
validityDays
=
30
}
}
if
validityDays
>
MaxValidityDays
{
validityDays
=
MaxValidityDays
}
now
:=
time
.
Now
()
now
:=
time
.
Now
()
expiresAt
:=
now
.
AddDate
(
0
,
0
,
validityDays
)
if
expiresAt
.
After
(
MaxExpiresAt
)
{
expiresAt
=
MaxExpiresAt
}
sub
:=
&
UserSubscription
{
sub
:=
&
UserSubscription
{
UserID
:
input
.
UserID
,
UserID
:
input
.
UserID
,
GroupID
:
input
.
GroupID
,
GroupID
:
input
.
GroupID
,
StartsAt
:
now
,
StartsAt
:
now
,
ExpiresAt
:
now
.
AddDate
(
0
,
0
,
validityDays
)
,
ExpiresAt
:
expiresAt
,
Status
:
SubscriptionStatusActive
,
Status
:
SubscriptionStatusActive
,
AssignedAt
:
now
,
AssignedAt
:
now
,
Notes
:
input
.
Notes
,
Notes
:
input
.
Notes
,
...
@@ -291,8 +314,17 @@ func (s *SubscriptionService) ExtendSubscription(ctx context.Context, subscripti
...
@@ -291,8 +314,17 @@ func (s *SubscriptionService) ExtendSubscription(ctx context.Context, subscripti
return
nil
,
ErrSubscriptionNotFound
return
nil
,
ErrSubscriptionNotFound
}
}
// 限制延长天数
if
days
>
MaxValidityDays
{
days
=
MaxValidityDays
}
// 计算新的过期时间
// 计算新的过期时间
newExpiresAt
:=
sub
.
ExpiresAt
.
AddDate
(
0
,
0
,
days
)
newExpiresAt
:=
sub
.
ExpiresAt
.
AddDate
(
0
,
0
,
days
)
if
newExpiresAt
.
After
(
MaxExpiresAt
)
{
newExpiresAt
=
MaxExpiresAt
}
if
err
:=
s
.
userSubRepo
.
ExtendExpiry
(
ctx
,
subscriptionID
,
newExpiresAt
);
err
!=
nil
{
if
err
:=
s
.
userSubRepo
.
ExtendExpiry
(
ctx
,
subscriptionID
,
newExpiresAt
);
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
...
backend/internal/service/timing_wheel_service.go
0 → 100644
View file @
295d71be
package
service
import
(
"log"
"sync"
"time"
"github.com/zeromicro/go-zero/core/collection"
)
// TimingWheelService wraps go-zero's TimingWheel for task scheduling
type
TimingWheelService
struct
{
tw
*
collection
.
TimingWheel
stopOnce
sync
.
Once
}
// NewTimingWheelService creates a new TimingWheelService instance
func
NewTimingWheelService
()
*
TimingWheelService
{
// 1 second tick, 3600 slots = supports up to 1 hour delay
// execute function: runs func() type tasks
tw
,
err
:=
collection
.
NewTimingWheel
(
1
*
time
.
Second
,
3600
,
func
(
key
,
value
any
)
{
if
fn
,
ok
:=
value
.
(
func
());
ok
{
fn
()
}
})
if
err
!=
nil
{
panic
(
err
)
}
return
&
TimingWheelService
{
tw
:
tw
}
}
// Start starts the timing wheel
func
(
s
*
TimingWheelService
)
Start
()
{
log
.
Println
(
"[TimingWheel] Started (auto-start by go-zero)"
)
}
// Stop stops the timing wheel
func
(
s
*
TimingWheelService
)
Stop
()
{
s
.
stopOnce
.
Do
(
func
()
{
s
.
tw
.
Stop
()
log
.
Println
(
"[TimingWheel] Stopped"
)
})
}
// Schedule schedules a one-time task
func
(
s
*
TimingWheelService
)
Schedule
(
name
string
,
delay
time
.
Duration
,
fn
func
())
{
_
=
s
.
tw
.
SetTimer
(
name
,
fn
,
delay
)
}
// ScheduleRecurring schedules a recurring task
func
(
s
*
TimingWheelService
)
ScheduleRecurring
(
name
string
,
interval
time
.
Duration
,
fn
func
())
{
var
schedule
func
()
schedule
=
func
()
{
fn
()
_
=
s
.
tw
.
SetTimer
(
name
,
schedule
,
interval
)
}
_
=
s
.
tw
.
SetTimer
(
name
,
schedule
,
interval
)
}
// Cancel cancels a scheduled task
func
(
s
*
TimingWheelService
)
Cancel
(
name
string
)
{
_
=
s
.
tw
.
RemoveTimer
(
name
)
}
backend/internal/service/token_refresh_service.go
View file @
295d71be
...
@@ -106,6 +106,9 @@ func (s *TokenRefreshService) processRefresh() {
...
@@ -106,6 +106,9 @@ func (s *TokenRefreshService) processRefresh() {
return
return
}
}
totalAccounts
:=
len
(
accounts
)
oauthAccounts
:=
0
// 可刷新的OAuth账号数
needsRefresh
:=
0
// 需要刷新的账号数
refreshed
,
failed
:=
0
,
0
refreshed
,
failed
:=
0
,
0
for
i
:=
range
accounts
{
for
i
:=
range
accounts
{
...
@@ -117,11 +120,15 @@ func (s *TokenRefreshService) processRefresh() {
...
@@ -117,11 +120,15 @@ func (s *TokenRefreshService) processRefresh() {
continue
continue
}
}
oauthAccounts
++
// 检查是否需要刷新
// 检查是否需要刷新
if
!
refresher
.
NeedsRefresh
(
account
,
refreshWindow
)
{
if
!
refresher
.
NeedsRefresh
(
account
,
refreshWindow
)
{
continue
break
// 不需要刷新,跳过
}
}
needsRefresh
++
// 执行刷新
// 执行刷新
if
err
:=
s
.
refreshWithRetry
(
ctx
,
account
,
refresher
);
err
!=
nil
{
if
err
:=
s
.
refreshWithRetry
(
ctx
,
account
,
refresher
);
err
!=
nil
{
log
.
Printf
(
"[TokenRefresh] Account %d (%s) failed: %v"
,
account
.
ID
,
account
.
Name
,
err
)
log
.
Printf
(
"[TokenRefresh] Account %d (%s) failed: %v"
,
account
.
ID
,
account
.
Name
,
err
)
...
@@ -136,9 +143,9 @@ func (s *TokenRefreshService) processRefresh() {
...
@@ -136,9 +143,9 @@ func (s *TokenRefreshService) processRefresh() {
}
}
}
}
if
refreshed
>
0
||
failed
>
0
{
// 始终打印周期日志,便于跟踪服务运行状态
log
.
Printf
(
"[TokenRefresh] Cycle complete:
%d refreshed, %d failed"
,
refreshed
,
failed
)
log
.
Printf
(
"[TokenRefresh] Cycle complete:
total=%d, oauth=%d, needs_refresh=%d
, refreshed
=%d
, failed
=%d"
,
}
totalAccounts
,
oauthAccounts
,
needsRefresh
,
refreshed
,
failed
)
}
}
// listActiveAccounts 获取所有active状态的账号
// listActiveAccounts 获取所有active状态的账号
...
...
backend/internal/service/token_refresher.go
View file @
295d71be
...
@@ -43,19 +43,13 @@ func (r *ClaudeTokenRefresher) CanRefresh(account *Account) bool {
...
@@ -43,19 +43,13 @@ func (r *ClaudeTokenRefresher) CanRefresh(account *Account) bool {
// NeedsRefresh 检查token是否需要刷新
// NeedsRefresh 检查token是否需要刷新
// 基于 expires_at 字段判断是否在刷新窗口内
// 基于 expires_at 字段判断是否在刷新窗口内
func
(
r
*
ClaudeTokenRefresher
)
NeedsRefresh
(
account
*
Account
,
refreshWindow
time
.
Duration
)
bool
{
func
(
r
*
ClaudeTokenRefresher
)
NeedsRefresh
(
account
*
Account
,
refreshWindow
time
.
Duration
)
bool
{
var
expiresAt
int64
s
:=
account
.
GetCredential
(
"expires_at"
)
if
s
==
""
{
// 方式1: 通过 GetCredential 获取(处理字符串和部分数字类型)
if
s
:=
account
.
GetCredential
(
"expires_at"
);
s
!=
""
{
v
,
err
:=
strconv
.
ParseInt
(
s
,
10
,
64
)
if
err
!=
nil
{
return
false
return
false
}
}
expiresAt
=
v
}
else
if
v
,
ok
:=
account
.
Credentials
[
"expires_at"
]
.
(
float64
);
ok
{
expiresAt
,
err
:=
strconv
.
ParseInt
(
s
,
10
,
64
)
// 方式2: 直接获取 float64(处理某些 JSON 解码器将数字解析为 float64 的情况)
if
err
!=
nil
{
expiresAt
=
int64
(
v
)
}
else
{
return
false
return
false
}
}
...
...
backend/internal/service/wire.go
View file @
295d71be
package
service
package
service
import
(
import
(
"time"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/google/wire"
"github.com/google/wire"
)
)
...
@@ -44,6 +46,20 @@ func ProvideTokenRefreshService(
...
@@ -44,6 +46,20 @@ func ProvideTokenRefreshService(
return
svc
return
svc
}
}
// ProvideTimingWheelService creates and starts TimingWheelService
func
ProvideTimingWheelService
()
*
TimingWheelService
{
svc
:=
NewTimingWheelService
()
svc
.
Start
()
return
svc
}
// ProvideDeferredService creates and starts DeferredService
func
ProvideDeferredService
(
accountRepo
AccountRepository
,
timingWheel
*
TimingWheelService
)
*
DeferredService
{
svc
:=
NewDeferredService
(
accountRepo
,
timingWheel
,
10
*
time
.
Second
)
svc
.
Start
()
return
svc
}
// ProviderSet is the Wire provider set for all services
// ProviderSet is the Wire provider set for all services
var
ProviderSet
=
wire
.
NewSet
(
var
ProviderSet
=
wire
.
NewSet
(
// Core services
// Core services
...
@@ -80,4 +96,6 @@ var ProviderSet = wire.NewSet(
...
@@ -80,4 +96,6 @@ var ProviderSet = wire.NewSet(
NewCRSSyncService
,
NewCRSSyncService
,
ProvideUpdateService
,
ProvideUpdateService
,
ProvideTokenRefreshService
,
ProvideTokenRefreshService
,
ProvideTimingWheelService
,
ProvideDeferredService
,
)
)
deploy/install.sh
View file @
295d71be
...
@@ -404,7 +404,9 @@ configure_server() {
...
@@ -404,7 +404,9 @@ configure_server() {
# Check if running as root
# Check if running as root
check_root
()
{
check_root
()
{
if
[
"
$EUID
"
-ne
0
]
;
then
# Use 'id -u' instead of $EUID for better compatibility
# $EUID may not work reliably when script is piped to bash
if
[
"
$(
id
-u
)
"
-ne
0
]
;
then
print_error
"
$(
msg
'run_as_root'
)
"
print_error
"
$(
msg
'run_as_root'
)
"
exit
1
exit
1
fi
fi
...
...
frontend/vite.config.d.ts
deleted
100644 → 0
View file @
1d1da736
declare
const
_default
:
import
(
'
vite
'
).
UserConfig
export
default
_default
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