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
3d79773b
Commit
3d79773b
authored
Mar 04, 2026
by
kyx236
Browse files
Merge branch 'main' of
https://github.com/james-6-23/sub2api
parents
6aa8cbbf
742e73c9
Changes
249
Hide whitespace changes
Inline
Side-by-side
Too many changes to show.
To preserve performance only
249 of 249+
files are displayed.
Plain diff
Email patch
.github/workflows/backend-ci.yml
View file @
3d79773b
...
@@ -11,8 +11,8 @@ jobs:
...
@@ -11,8 +11,8 @@ jobs:
test
:
test
:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
uses
:
actions/checkout@v
4
-
uses
:
actions/checkout@v
6
-
uses
:
actions/setup-go@v
5
-
uses
:
actions/setup-go@v
6
with
:
with
:
go-version-file
:
backend/go.mod
go-version-file
:
backend/go.mod
check-latest
:
false
check-latest
:
false
...
@@ -30,8 +30,8 @@ jobs:
...
@@ -30,8 +30,8 @@ jobs:
golangci-lint
:
golangci-lint
:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
uses
:
actions/checkout@v
4
-
uses
:
actions/checkout@v
6
-
uses
:
actions/setup-go@v
5
-
uses
:
actions/setup-go@v
6
with
:
with
:
go-version-file
:
backend/go.mod
go-version-file
:
backend/go.mod
check-latest
:
false
check-latest
:
false
...
@@ -43,5 +43,5 @@ jobs:
...
@@ -43,5 +43,5 @@ jobs:
uses
:
golangci/golangci-lint-action@v9
uses
:
golangci/golangci-lint-action@v9
with
:
with
:
version
:
v2.7
version
:
v2.7
args
:
--timeout=
5
m
args
:
--timeout=
30
m
working-directory
:
backend
working-directory
:
backend
\ No newline at end of file
.github/workflows/release.yml
View file @
3d79773b
...
@@ -31,7 +31,7 @@ jobs:
...
@@ -31,7 +31,7 @@ jobs:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
name
:
Checkout
-
name
:
Checkout
uses
:
actions/checkout@v
4
uses
:
actions/checkout@v
6
-
name
:
Update VERSION file
-
name
:
Update VERSION file
run
:
|
run
:
|
...
@@ -45,7 +45,7 @@ jobs:
...
@@ -45,7 +45,7 @@ jobs:
echo "Updated VERSION file to: $VERSION"
echo "Updated VERSION file to: $VERSION"
-
name
:
Upload VERSION artifact
-
name
:
Upload VERSION artifact
uses
:
actions/upload-artifact@v
4
uses
:
actions/upload-artifact@v
7
with
:
with
:
name
:
version-file
name
:
version-file
path
:
backend/cmd/server/VERSION
path
:
backend/cmd/server/VERSION
...
@@ -55,7 +55,7 @@ jobs:
...
@@ -55,7 +55,7 @@ jobs:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
name
:
Checkout
-
name
:
Checkout
uses
:
actions/checkout@v
4
uses
:
actions/checkout@v
6
-
name
:
Setup pnpm
-
name
:
Setup pnpm
uses
:
pnpm/action-setup@v4
uses
:
pnpm/action-setup@v4
...
@@ -63,7 +63,7 @@ jobs:
...
@@ -63,7 +63,7 @@ jobs:
version
:
9
version
:
9
-
name
:
Setup Node.js
-
name
:
Setup Node.js
uses
:
actions/setup-node@v
4
uses
:
actions/setup-node@v
6
with
:
with
:
node-version
:
'
20'
node-version
:
'
20'
cache
:
'
pnpm'
cache
:
'
pnpm'
...
@@ -78,7 +78,7 @@ jobs:
...
@@ -78,7 +78,7 @@ jobs:
working-directory
:
frontend
working-directory
:
frontend
-
name
:
Upload frontend artifact
-
name
:
Upload frontend artifact
uses
:
actions/upload-artifact@v
4
uses
:
actions/upload-artifact@v
7
with
:
with
:
name
:
frontend-dist
name
:
frontend-dist
path
:
backend/internal/web/dist/
path
:
backend/internal/web/dist/
...
@@ -89,25 +89,25 @@ jobs:
...
@@ -89,25 +89,25 @@ jobs:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
name
:
Checkout
-
name
:
Checkout
uses
:
actions/checkout@v
4
uses
:
actions/checkout@v
6
with
:
with
:
fetch-depth
:
0
fetch-depth
:
0
ref
:
${{ github.event.inputs.tag || github.ref }}
ref
:
${{ github.event.inputs.tag || github.ref }}
-
name
:
Download VERSION artifact
-
name
:
Download VERSION artifact
uses
:
actions/download-artifact@v
4
uses
:
actions/download-artifact@v
8
with
:
with
:
name
:
version-file
name
:
version-file
path
:
backend/cmd/server/
path
:
backend/cmd/server/
-
name
:
Download frontend artifact
-
name
:
Download frontend artifact
uses
:
actions/download-artifact@v
4
uses
:
actions/download-artifact@v
8
with
:
with
:
name
:
frontend-dist
name
:
frontend-dist
path
:
backend/internal/web/dist/
path
:
backend/internal/web/dist/
-
name
:
Setup Go
-
name
:
Setup Go
uses
:
actions/setup-go@v
5
uses
:
actions/setup-go@v
6
with
:
with
:
go-version-file
:
backend/go.mod
go-version-file
:
backend/go.mod
check-latest
:
false
check-latest
:
false
...
@@ -173,7 +173,7 @@ jobs:
...
@@ -173,7 +173,7 @@ jobs:
run
:
echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
run
:
echo "owner=$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
-
name
:
Run GoReleaser
-
name
:
Run GoReleaser
uses
:
goreleaser/goreleaser-action@v
6
uses
:
goreleaser/goreleaser-action@v
7
with
:
with
:
version
:
'
~>
v2'
version
:
'
~>
v2'
args
:
release --clean --skip=validate ${{ env.SIMPLE_RELEASE == 'true' && '--config=.goreleaser.simple.yaml' || '' }}
args
:
release --clean --skip=validate ${{ env.SIMPLE_RELEASE == 'true' && '--config=.goreleaser.simple.yaml' || '' }}
...
@@ -188,7 +188,7 @@ jobs:
...
@@ -188,7 +188,7 @@ jobs:
# Update DockerHub description
# Update DockerHub description
-
name
:
Update DockerHub description
-
name
:
Update DockerHub description
if
:
${{ env.SIMPLE_RELEASE != 'true' && env.DOCKERHUB_USERNAME != '' }}
if
:
${{ env.SIMPLE_RELEASE != 'true' && env.DOCKERHUB_USERNAME != '' }}
uses
:
peter-evans/dockerhub-description@v
4
uses
:
peter-evans/dockerhub-description@v
5
env
:
env
:
DOCKERHUB_USERNAME
:
${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_USERNAME
:
${{ secrets.DOCKERHUB_USERNAME }}
with
:
with
:
...
...
.github/workflows/security-scan.yml
View file @
3d79773b
...
@@ -12,10 +12,11 @@ permissions:
...
@@ -12,10 +12,11 @@ permissions:
jobs
:
jobs
:
backend-security
:
backend-security
:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
timeout-minutes
:
15
steps
:
steps
:
-
uses
:
actions/checkout@v
4
-
uses
:
actions/checkout@v
6
-
name
:
Set up Go
-
name
:
Set up Go
uses
:
actions/setup-go@v
5
uses
:
actions/setup-go@v
6
with
:
with
:
go-version-file
:
backend/go.mod
go-version-file
:
backend/go.mod
check-latest
:
false
check-latest
:
false
...
@@ -28,22 +29,17 @@ jobs:
...
@@ -28,22 +29,17 @@ jobs:
run
:
|
run
:
|
go install golang.org/x/vuln/cmd/govulncheck@latest
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
govulncheck ./...
-
name
:
Run gosec
working-directory
:
backend
run
:
|
go install github.com/securego/gosec/v2/cmd/gosec@latest
gosec -severity high -confidence high ./...
frontend-security
:
frontend-security
:
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
uses
:
actions/checkout@v
4
-
uses
:
actions/checkout@v
6
-
name
:
Set up pnpm
-
name
:
Set up pnpm
uses
:
pnpm/action-setup@v4
uses
:
pnpm/action-setup@v4
with
:
with
:
version
:
9
version
:
9
-
name
:
Set up Node.js
-
name
:
Set up Node.js
uses
:
actions/setup-node@v
4
uses
:
actions/setup-node@v
6
with
:
with
:
node-version
:
'
20'
node-version
:
'
20'
cache
:
'
pnpm'
cache
:
'
pnpm'
...
...
.gitignore
View file @
3d79773b
...
@@ -116,17 +116,20 @@ backend/.installed
...
@@ -116,17 +116,20 @@ backend/.installed
# ===================
# ===================
tests
tests
CLAUDE.md
CLAUDE.md
AGENTS.md
.claude
.claude
scripts
scripts
.code-review-state
.code-review-state
openspec/
#openspec/
docs/
code-reviews/
code-reviews/
AGENTS.md
#
AGENTS.md
backend/cmd/server/server
backend/cmd/server/server
deploy/docker-compose.override.yml
deploy/docker-compose.override.yml
.gocache/
.gocache/
vite.config.js
vite.config.js
docs/*
docs/*
.serena/
.serena/
\ No newline at end of file
.codex/
frontend/coverage/
aicodex
output/
DEV_GUIDE.md
View file @
3d79773b
...
@@ -209,7 +209,30 @@ git add ent/ # 生成的文件也要提交
...
@@ -209,7 +209,30 @@ git add ent/ # 生成的文件也要提交
---
---
### 坑 10:PR 提交前检查清单
### 坑 10:前端测试看似正常,但后端调用失败(模型映射被批量误改)
**典型现象**
:
-
前端按钮点测看起来正常;
-
实际通过 API/客户端调用时返回
`Service temporarily unavailable`
或提示无可用账号;
-
常见于 OpenAI 账号(例如 Codex 模型)在批量修改后突然不可用。
**根因**
:
-
OpenAI 账号编辑页默认不显式展示映射规则,容易让人误以为“没映射也没关系”;
-
但在
**批量修改同时选中不同平台账号**
(OpenAI + Antigravity/Gemini)时,模型白名单/映射可能被跨平台策略覆盖;
-
结果是 OpenAI 账号的关键模型映射丢失或被改坏,后端选不到可用账号。
**修复方案(按优先级)**
:
1.
**快速修复(推荐)**
:在批量修改中补回正确的透传映射(例如
`gpt-5.3-codex -> gpt-5.3-codex-spark`
)。
2.
**彻底重建**
:删除并重新添加全部相关账号(最稳但成本高)。
**关键经验**
:
-
如果某模型已被软件内置默认映射覆盖,通常不需要额外再加透传;
-
但当上游模型更新快于本仓库默认映射时,
**手动批量添加透传映射**
是最简单、最低风险的临时兜底方案;
-
批量操作前尽量按平台分组,不要混选不同平台账号。
---
### 坑 11:PR 提交前检查清单
提交 PR 前务必本地验证:
提交 PR 前务必本地验证:
...
...
Dockerfile
View file @
3d79773b
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
ARG
NODE_IMAGE=node:24-alpine
ARG
NODE_IMAGE=node:24-alpine
ARG
GOLANG_IMAGE=golang:1.25.7-alpine
ARG
GOLANG_IMAGE=golang:1.25.7-alpine
ARG
ALPINE_IMAGE=alpine:3.2
0
ARG
ALPINE_IMAGE=alpine:3.2
1
ARG
GOPROXY=https://goproxy.cn,direct
ARG
GOPROXY=https://goproxy.cn,direct
ARG
GOSUMDB=sum.golang.google.cn
ARG
GOSUMDB=sum.golang.google.cn
...
@@ -36,7 +36,7 @@ RUN pnpm run build
...
@@ -36,7 +36,7 @@ RUN pnpm run build
FROM
${GOLANG_IMAGE} AS backend-builder
FROM
${GOLANG_IMAGE} AS backend-builder
# Build arguments for version info (set by CI)
# Build arguments for version info (set by CI)
ARG
VERSION=
docker
ARG
VERSION=
ARG
COMMIT=docker
ARG
COMMIT=docker
ARG
DATE
ARG
DATE
ARG
GOPROXY
ARG
GOPROXY
...
@@ -61,9 +61,14 @@ COPY backend/ ./
...
@@ -61,9 +61,14 @@ COPY backend/ ./
COPY
--from=frontend-builder /app/backend/internal/web/dist ./internal/web/dist
COPY
--from=frontend-builder /app/backend/internal/web/dist ./internal/web/dist
# Build the binary (BuildType=release for CI builds, embed frontend)
# Build the binary (BuildType=release for CI builds, embed frontend)
RUN
CGO_ENABLED
=
0
GOOS
=
linux go build
\
# Version precedence: build arg VERSION > cmd/server/VERSION
RUN
VERSION_VALUE
=
"
${
VERSION
}
"
&&
\
if
[
-z
"
${
VERSION_VALUE
}
"
]
;
then
VERSION_VALUE
=
"
$(
tr
-d
'\r\n'
< ./cmd/server/VERSION
)
"
;
fi
&&
\
DATE_VALUE
=
"
${
DATE
:-
$(
date
-u
+%Y-%m-%dT%H:%M:%SZ
)
}
"
&&
\
CGO_ENABLED
=
0
GOOS
=
linux go build
\
-tags
embed
\
-tags
embed
\
-ldflags
=
"-s -w -X main.Commit=
${
COMMIT
}
-X main.Date=
${
DATE
:-
$(
date
-u
+%Y-%m-%dT%H:%M:%SZ
)
}
-X main.BuildType=release"
\
-ldflags
=
"-s -w -X main.Version=
${
VERSION_VALUE
}
-X main.Commit=
${
COMMIT
}
-X main.Date=
${
DATE_VALUE
}
-X main.BuildType=release"
\
-trimpath
\
-o
/app/sub2api
\
-o
/app/sub2api
\
./cmd/server
./cmd/server
...
@@ -81,7 +86,6 @@ LABEL org.opencontainers.image.source="https://github.com/Wei-Shaw/sub2api"
...
@@ -81,7 +86,6 @@ LABEL org.opencontainers.image.source="https://github.com/Wei-Shaw/sub2api"
RUN
apk add
--no-cache
\
RUN
apk add
--no-cache
\
ca-certificates
\
ca-certificates
\
tzdata
\
tzdata
\
curl
\
&&
rm
-rf
/var/cache/apk/
*
&&
rm
-rf
/var/cache/apk/
*
# Create non-root user
# Create non-root user
...
@@ -91,11 +95,12 @@ RUN addgroup -g 1000 sub2api && \
...
@@ -91,11 +95,12 @@ RUN addgroup -g 1000 sub2api && \
# Set working directory
# Set working directory
WORKDIR
/app
WORKDIR
/app
# Copy binary from builder
# Copy binary/resources with ownership to avoid extra full-layer chown copy
COPY
--from=backend-builder /app/sub2api /app/sub2api
COPY
--from=backend-builder --chown=sub2api:sub2api /app/sub2api /app/sub2api
COPY
--from=backend-builder --chown=sub2api:sub2api /app/backend/resources /app/resources
# Create data directory
# Create data directory
RUN
mkdir
-p
/app/data
&&
chown
-R
sub2api:sub2api /app
RUN
mkdir
-p
/app/data
&&
chown
sub2api:sub2api /app
/data
# Switch to non-root user
# Switch to non-root user
USER
sub2api
USER
sub2api
...
@@ -105,7 +110,7 @@ EXPOSE 8080
...
@@ -105,7 +110,7 @@ EXPOSE 8080
# Health check
# Health check
HEALTHCHECK
--interval=30s --timeout=10s --start-period=10s --retries=3 \
HEALTHCHECK
--interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD
curl -f
http://localhost:${SERVER_PORT:-8080}/health || exit 1
CMD
wget -q -T 5 -O /dev/null
http://localhost:${SERVER_PORT:-8080}/health || exit 1
# Run the application
# Run the application
ENTRYPOINT
["/app/sub2api"]
ENTRYPOINT
["/app/sub2api"]
Makefile
View file @
3d79773b
.PHONY
:
build build-backend build-frontend test test-backend test-frontend
.PHONY
:
build build-backend build-frontend
build-datamanagementd
test test-backend test-frontend
test-datamanagementd secret-scan
# 一键编译前后端
# 一键编译前后端
build
:
build-backend build-frontend
build
:
build-backend build-frontend
...
@@ -11,6 +11,10 @@ build-backend:
...
@@ -11,6 +11,10 @@ build-backend:
build-frontend
:
build-frontend
:
@
pnpm
--dir
frontend run build
@
pnpm
--dir
frontend run build
# 编译 datamanagementd(宿主机数据管理进程)
build-datamanagementd
:
@
cd
datamanagement
&&
go build
-o
datamanagementd ./cmd/datamanagementd
# 运行测试(后端 + 前端)
# 运行测试(后端 + 前端)
test
:
test-backend test-frontend
test
:
test-backend test-frontend
...
@@ -20,3 +24,9 @@ test-backend:
...
@@ -20,3 +24,9 @@ test-backend:
test-frontend
:
test-frontend
:
@
pnpm
--dir
frontend run lint:check
@
pnpm
--dir
frontend run lint:check
@
pnpm
--dir
frontend run typecheck
@
pnpm
--dir
frontend run typecheck
test-datamanagementd
:
@
cd
datamanagement
&&
go
test
./...
secret-scan
:
@
python3 tools/secret_scan.py
README.md
View file @
3d79773b
...
@@ -54,6 +54,7 @@ Sub2API is an AI API gateway platform designed to distribute and manage API quot
...
@@ -54,6 +54,7 @@ Sub2API is an AI API gateway platform designed to distribute and manage API quot
## Documentation
## Documentation
-
Dependency Security:
`docs/dependency-security.md`
-
Dependency Security:
`docs/dependency-security.md`
-
Admin Payment Integration API:
`docs/ADMIN_PAYMENT_INTEGRATION_API.md`
---
---
...
@@ -363,6 +364,12 @@ default:
...
@@ -363,6 +364,12 @@ default:
rate_multiplier
:
1.0
rate_multiplier
:
1.0
```
```
### Sora Status (Temporarily Unavailable)
> ⚠️ Sora-related features are temporarily unavailable due to technical issues in upstream integration and media delivery.
> Please do not rely on Sora in production at this time.
> Existing `gateway.sora_*` configuration keys are reserved and may not take effect until these issues are resolved.
Additional security-related options are available in
`config.yaml`
:
Additional security-related options are available in
`config.yaml`
:
-
`cors.allowed_origins`
for CORS allowlist
-
`cors.allowed_origins`
for CORS allowlist
...
...
README_CN.md
View file @
3d79773b
...
@@ -62,8 +62,6 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅(
...
@@ -62,8 +62,6 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅(
-
当请求包含
`function_call_output`
时,需要携带
`previous_response_id`
,或在
`input`
中包含带
`call_id`
的
`tool_call`
/
`function_call`
,或带非空
`id`
且与
`function_call_output.call_id`
匹配的
`item_reference`
。
-
当请求包含
`function_call_output`
时,需要携带
`previous_response_id`
,或在
`input`
中包含带
`call_id`
的
`tool_call`
/
`function_call`
,或带非空
`id`
且与
`function_call_output.call_id`
匹配的
`item_reference`
。
-
若依赖上游历史记录,网关会强制
`store=true`
并需要复用
`previous_response_id`
,以避免出现 “No tool call found for function call output” 错误。
-
若依赖上游历史记录,网关会强制
`store=true`
并需要复用
`previous_response_id`
,以避免出现 “No tool call found for function call output” 错误。
---
## 部署方式
## 部署方式
### 方式一:脚本安装(推荐)
### 方式一:脚本安装(推荐)
...
@@ -244,6 +242,18 @@ docker-compose -f docker-compose.local.yml logs -f sub2api
...
@@ -244,6 +242,18 @@ docker-compose -f docker-compose.local.yml logs -f sub2api
**推荐:**
使用
`docker-compose.local.yml`
(脚本部署)以便更轻松地管理数据。
**推荐:**
使用
`docker-compose.local.yml`
(脚本部署)以便更轻松地管理数据。
#### 启用“数据管理”功能(datamanagementd)
如需启用管理后台“数据管理”,需要额外部署宿主机数据管理进程
`datamanagementd`
。
关键点:
-
主进程固定探测:
`/tmp/sub2api-datamanagement.sock`
-
只有该 Socket 可连通时,数据管理功能才会开启
-
Docker 场景需将宿主机 Socket 挂载到容器同路径
详细部署步骤见:
`deploy/DATAMANAGEMENTD_CN.md`
#### 访问
#### 访问
在浏览器中打开
`http://你的服务器IP:8080`
在浏览器中打开
`http://你的服务器IP:8080`
...
@@ -370,6 +380,33 @@ default:
...
@@ -370,6 +380,33 @@ default:
rate_multiplier
:
1.0
rate_multiplier
:
1.0
```
```
### Sora 功能状态(暂不可用)
> ⚠️ 当前 Sora 相关功能因上游接入与媒体链路存在技术问题,暂时不可用。
> 现阶段请勿在生产环境依赖 Sora 能力。
> 文档中的 `gateway.sora_*` 配置仅作预留,待技术问题修复后再恢复可用。
### Sora 媒体签名 URL(功能恢复后可选)
当配置
`gateway.sora_media_signing_key`
且
`gateway.sora_media_signed_url_ttl_seconds > 0`
时,网关会将 Sora 输出的媒体地址改写为临时签名 URL(
`/sora/media-signed/...`
)。这样无需 API Key 即可在浏览器中直接访问,且具备过期控制与防篡改能力(签名包含 path + query)。
```
yaml
gateway
:
# /sora/media 是否强制要求 API Key(默认 false)
sora_media_require_api_key
:
false
# 媒体临时签名密钥(为空则禁用签名)
sora_media_signing_key
:
"
your-signing-key"
# 临时签名 URL 有效期(秒)
sora_media_signed_url_ttl_seconds
:
900
```
> 若未配置签名密钥,`/sora/media-signed` 将返回 503。
> 如需更严格的访问控制,可将 `sora_media_require_api_key` 设为 true,仅允许携带 API Key 的 `/sora/media` 访问。
访问策略说明:
-
`/sora/media`
:内部调用或客户端携带 API Key 才能下载
-
`/sora/media-signed`
:外部可访问,但有签名 + 过期控制
`config.yaml`
还支持以下安全相关配置:
`config.yaml`
还支持以下安全相关配置:
-
`cors.allowed_origins`
配置 CORS 白名单
-
`cors.allowed_origins`
配置 CORS 白名单
...
@@ -383,6 +420,14 @@ default:
...
@@ -383,6 +420,14 @@ default:
-
`server.trusted_proxies`
启用可信代理解析 X-Forwarded-For
-
`server.trusted_proxies`
启用可信代理解析 X-Forwarded-For
-
`turnstile.required`
在 release 模式强制启用 Turnstile
-
`turnstile.required`
在 release 模式强制启用 Turnstile
**网关防御纵深建议(重点)**
-
`gateway.upstream_response_read_max_bytes`
:限制非流式上游响应读取大小(默认
`8MB`
),用于防止异常响应导致内存放大。
-
`gateway.proxy_probe_response_read_max_bytes`
:限制代理探测响应读取大小(默认
`1MB`
)。
-
`gateway.gemini_debug_response_headers`
:默认
`false`
,仅在排障时短时开启,避免高频请求日志开销。
-
`/auth/register`
、
`/auth/login`
、
`/auth/login/2fa`
、
`/auth/send-verify-code`
已提供服务端兜底限流(Redis 故障时 fail-close)。
-
推荐将 WAF/CDN 作为第一层防护,服务端限流与响应读取上限作为第二层兜底;两层同时保留,避免旁路流量与误配置风险。
**⚠️ 安全警告:HTTP URL 配置**
**⚠️ 安全警告:HTTP URL 配置**
当
`security.url_allowlist.enabled=false`
时,系统默认执行最小 URL 校验,
**拒绝 HTTP URL**
,仅允许 HTTPS。要允许 HTTP URL(例如用于开发或内网测试),必须显式设置:
当
`security.url_allowlist.enabled=false`
时,系统默认执行最小 URL 校验,
**拒绝 HTTP URL**
,仅允许 HTTPS。要允许 HTTP URL(例如用于开发或内网测试),必须显式设置:
...
@@ -428,6 +473,29 @@ Invalid base URL: invalid url scheme: http
...
@@ -428,6 +473,29 @@ Invalid base URL: invalid url scheme: http
./sub2api
./sub2api
```
```
#### HTTP/2 (h2c) 与 HTTP/1.1 回退
后端明文端口默认支持 h2c,并保留 HTTP/1.1 回退用于 WebSocket 与旧客户端。浏览器通常不支持 h2c,性能收益主要在反向代理或内网链路。
**反向代理示例(Caddy):**
```
caddyfile
transport http {
versions h2c h1
}
```
**验证:**
```
bash
# h2c prior knowledge
curl
--http2-prior-knowledge
-I
http://localhost:8080/health
# HTTP/1.1 回退
curl
--http1
.1
-I
http://localhost:8080/health
# WebSocket 回退验证(需管理员 token)
websocat
-H
=
"Sec-WebSocket-Protocol: sub2api-admin, jwt.<ADMIN_TOKEN>"
ws://localhost:8080/api/v1/admin/ops/ws/qps
```
#### 开发模式
#### 开发模式
```
bash
```
bash
...
...
backend/.golangci.yml
View file @
3d79773b
...
@@ -5,6 +5,7 @@ linters:
...
@@ -5,6 +5,7 @@ linters:
enable
:
enable
:
-
depguard
-
depguard
-
errcheck
-
errcheck
-
gosec
-
govet
-
govet
-
ineffassign
-
ineffassign
-
staticcheck
-
staticcheck
...
@@ -42,6 +43,22 @@ linters:
...
@@ -42,6 +43,22 @@ linters:
desc
:
"
handler
must
not
import
gorm"
desc
:
"
handler
must
not
import
gorm"
-
pkg
:
github.com/redis/go-redis/v9
-
pkg
:
github.com/redis/go-redis/v9
desc
:
"
handler
must
not
import
redis"
desc
:
"
handler
must
not
import
redis"
gosec
:
excludes
:
-
G101
-
G103
-
G104
-
G109
-
G115
-
G201
-
G202
-
G301
-
G302
-
G304
-
G306
-
G404
severity
:
high
confidence
:
high
errcheck
:
errcheck
:
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
# Such cases aren't reported by default.
# Such cases aren't reported by default.
...
...
backend/Makefile
View file @
3d79773b
.PHONY
:
build test test-unit test-integration test-e2e
.PHONY
:
build generate test test-unit test-integration test-e2e
VERSION
?=
$(
shell
tr
-d
'\r\n'
< ./cmd/server/VERSION
)
LDFLAGS
?=
-s
-w
-X
main.Version
=
$(VERSION)
build
:
build
:
go build
-o
bin/server ./cmd/server
CGO_ENABLED
=
0 go build
-ldflags
=
"
$(LDFLAGS)
"
-trimpath
-o
bin/server ./cmd/server
generate
:
go generate ./ent
go generate ./cmd/server
test
:
test
:
go
test
./...
go
test
./...
...
@@ -14,4 +21,7 @@ test-integration:
...
@@ -14,4 +21,7 @@ test-integration:
go
test
-tags
=
integration ./...
go
test
-tags
=
integration ./...
test-e2e
:
test-e2e
:
go
test
-tags
=
e2e ./...
./scripts/e2e-test.sh
test-e2e-local
:
go
test
-tags
=
e2e
-v
-timeout
=
300s ./internal/integration/...
backend/cmd/jwtgen/main.go
View file @
3d79773b
...
@@ -17,7 +17,7 @@ func main() {
...
@@ -17,7 +17,7 @@ func main() {
email
:=
flag
.
String
(
"email"
,
""
,
"Admin email to issue a JWT for (defaults to first active admin)"
)
email
:=
flag
.
String
(
"email"
,
""
,
"Admin email to issue a JWT for (defaults to first active admin)"
)
flag
.
Parse
()
flag
.
Parse
()
cfg
,
err
:=
config
.
Load
()
cfg
,
err
:=
config
.
Load
ForBootstrap
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Fatalf
(
"failed to load config: %v"
,
err
)
log
.
Fatalf
(
"failed to load config: %v"
,
err
)
}
}
...
@@ -33,7 +33,7 @@ func main() {
...
@@ -33,7 +33,7 @@ func main() {
}()
}()
userRepo
:=
repository
.
NewUserRepository
(
client
,
sqlDB
)
userRepo
:=
repository
.
NewUserRepository
(
client
,
sqlDB
)
authService
:=
service
.
NewAuthService
(
userRepo
,
nil
,
nil
,
cfg
,
nil
,
nil
,
nil
,
nil
,
nil
)
authService
:=
service
.
NewAuthService
(
userRepo
,
nil
,
nil
,
cfg
,
nil
,
nil
,
nil
,
nil
,
nil
,
nil
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
defer
cancel
()
defer
cancel
()
...
...
backend/cmd/server/VERSION
View file @
3d79773b
0.1.76
0.1.88
\ No newline at end of file
\ No newline at end of file
backend/cmd/server/main.go
View file @
3d79773b
...
@@ -8,7 +8,6 @@ import (
...
@@ -8,7 +8,6 @@ import (
"errors"
"errors"
"flag"
"flag"
"log"
"log"
"log/slog"
"net/http"
"net/http"
"os"
"os"
"os/signal"
"os/signal"
...
@@ -19,11 +18,14 @@ import (
...
@@ -19,11 +18,14 @@ import (
_
"github.com/Wei-Shaw/sub2api/ent/runtime"
_
"github.com/Wei-Shaw/sub2api/ent/runtime"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/handler"
"github.com/Wei-Shaw/sub2api/internal/handler"
"github.com/Wei-Shaw/sub2api/internal/pkg/logger"
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/setup"
"github.com/Wei-Shaw/sub2api/internal/setup"
"github.com/Wei-Shaw/sub2api/internal/web"
"github.com/Wei-Shaw/sub2api/internal/web"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
)
//go:embed VERSION
//go:embed VERSION
...
@@ -38,7 +40,12 @@ var (
...
@@ -38,7 +40,12 @@ var (
)
)
func
init
()
{
func
init
()
{
// Read version from embedded VERSION file
// 如果 Version 已通过 ldflags 注入(例如 -X main.Version=...),则不要覆盖。
if
strings
.
TrimSpace
(
Version
)
!=
""
{
return
}
// 默认从 embedded VERSION 文件读取版本号(编译期打包进二进制)。
Version
=
strings
.
TrimSpace
(
embeddedVersion
)
Version
=
strings
.
TrimSpace
(
embeddedVersion
)
if
Version
==
""
{
if
Version
==
""
{
Version
=
"0.0.0-dev"
Version
=
"0.0.0-dev"
...
@@ -47,22 +54,9 @@ func init() {
...
@@ -47,22 +54,9 @@ func init() {
// initLogger configures the default slog handler based on gin.Mode().
// initLogger configures the default slog handler based on gin.Mode().
// In non-release mode, Debug level logs are enabled.
// In non-release mode, Debug level logs are enabled.
func
initLogger
()
{
var
level
slog
.
Level
if
gin
.
Mode
()
==
gin
.
ReleaseMode
{
level
=
slog
.
LevelInfo
}
else
{
level
=
slog
.
LevelDebug
}
handler
:=
slog
.
NewTextHandler
(
os
.
Stderr
,
&
slog
.
HandlerOptions
{
Level
:
level
,
})
slog
.
SetDefault
(
slog
.
New
(
handler
))
}
func
main
()
{
func
main
()
{
// Initialize slog logger based on gin mode
logger
.
InitBootstrap
()
initLogger
()
defer
logger
.
Sync
()
// Parse command line flags
// Parse command line flags
setupMode
:=
flag
.
Bool
(
"setup"
,
false
,
"Run setup wizard in CLI mode"
)
setupMode
:=
flag
.
Bool
(
"setup"
,
false
,
"Run setup wizard in CLI mode"
)
...
@@ -106,7 +100,7 @@ func runSetupServer() {
...
@@ -106,7 +100,7 @@ func runSetupServer() {
r
:=
gin
.
New
()
r
:=
gin
.
New
()
r
.
Use
(
middleware
.
Recovery
())
r
.
Use
(
middleware
.
Recovery
())
r
.
Use
(
middleware
.
CORS
(
config
.
CORSConfig
{}))
r
.
Use
(
middleware
.
CORS
(
config
.
CORSConfig
{}))
r
.
Use
(
middleware
.
SecurityHeaders
(
config
.
CSPConfig
{
Enabled
:
true
,
Policy
:
config
.
DefaultCSPPolicy
}))
r
.
Use
(
middleware
.
SecurityHeaders
(
config
.
CSPConfig
{
Enabled
:
true
,
Policy
:
config
.
DefaultCSPPolicy
}
,
nil
))
// Register setup routes
// Register setup routes
setup
.
RegisterRoutes
(
r
)
setup
.
RegisterRoutes
(
r
)
...
@@ -122,16 +116,26 @@ func runSetupServer() {
...
@@ -122,16 +116,26 @@ func runSetupServer() {
log
.
Printf
(
"Setup wizard available at http://%s"
,
addr
)
log
.
Printf
(
"Setup wizard available at http://%s"
,
addr
)
log
.
Println
(
"Complete the setup wizard to configure Sub2API"
)
log
.
Println
(
"Complete the setup wizard to configure Sub2API"
)
if
err
:=
r
.
Run
(
addr
);
err
!=
nil
{
server
:=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
h2c
.
NewHandler
(
r
,
&
http2
.
Server
{}),
ReadHeaderTimeout
:
30
*
time
.
Second
,
IdleTimeout
:
120
*
time
.
Second
,
}
if
err
:=
server
.
ListenAndServe
();
err
!=
nil
&&
!
errors
.
Is
(
err
,
http
.
ErrServerClosed
)
{
log
.
Fatalf
(
"Failed to start setup server: %v"
,
err
)
log
.
Fatalf
(
"Failed to start setup server: %v"
,
err
)
}
}
}
}
func
runMainServer
()
{
func
runMainServer
()
{
cfg
,
err
:=
config
.
Load
()
cfg
,
err
:=
config
.
Load
ForBootstrap
()
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Fatalf
(
"Failed to load config: %v"
,
err
)
log
.
Fatalf
(
"Failed to load config: %v"
,
err
)
}
}
if
err
:=
logger
.
Init
(
logger
.
OptionsFromConfig
(
cfg
.
Log
));
err
!=
nil
{
log
.
Fatalf
(
"Failed to initialize logger: %v"
,
err
)
}
if
cfg
.
RunMode
==
config
.
RunModeSimple
{
if
cfg
.
RunMode
==
config
.
RunModeSimple
{
log
.
Println
(
"⚠️ WARNING: Running in SIMPLE mode - billing and quota checks are DISABLED"
)
log
.
Println
(
"⚠️ WARNING: Running in SIMPLE mode - billing and quota checks are DISABLED"
)
}
}
...
...
backend/cmd/server/wire.go
View file @
3d79773b
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"context"
"context"
"log"
"log"
"net/http"
"net/http"
"sync"
"time"
"time"
"github.com/Wei-Shaw/sub2api/ent"
"github.com/Wei-Shaw/sub2api/ent"
...
@@ -67,28 +68,36 @@ func provideCleanup(
...
@@ -67,28 +68,36 @@ func provideCleanup(
opsAlertEvaluator
*
service
.
OpsAlertEvaluatorService
,
opsAlertEvaluator
*
service
.
OpsAlertEvaluatorService
,
opsCleanup
*
service
.
OpsCleanupService
,
opsCleanup
*
service
.
OpsCleanupService
,
opsScheduledReport
*
service
.
OpsScheduledReportService
,
opsScheduledReport
*
service
.
OpsScheduledReportService
,
opsSystemLogSink
*
service
.
OpsSystemLogSink
,
soraMediaCleanup
*
service
.
SoraMediaCleanupService
,
schedulerSnapshot
*
service
.
SchedulerSnapshotService
,
schedulerSnapshot
*
service
.
SchedulerSnapshotService
,
tokenRefresh
*
service
.
TokenRefreshService
,
tokenRefresh
*
service
.
TokenRefreshService
,
accountExpiry
*
service
.
AccountExpiryService
,
accountExpiry
*
service
.
AccountExpiryService
,
subscriptionExpiry
*
service
.
SubscriptionExpiryService
,
subscriptionExpiry
*
service
.
SubscriptionExpiryService
,
usageCleanup
*
service
.
UsageCleanupService
,
usageCleanup
*
service
.
UsageCleanupService
,
idempotencyCleanup
*
service
.
IdempotencyCleanupService
,
pricing
*
service
.
PricingService
,
pricing
*
service
.
PricingService
,
emailQueue
*
service
.
EmailQueueService
,
emailQueue
*
service
.
EmailQueueService
,
billingCache
*
service
.
BillingCacheService
,
billingCache
*
service
.
BillingCacheService
,
usageRecordWorkerPool
*
service
.
UsageRecordWorkerPool
,
subscriptionService
*
service
.
SubscriptionService
,
oauth
*
service
.
OAuthService
,
oauth
*
service
.
OAuthService
,
openaiOAuth
*
service
.
OpenAIOAuthService
,
openaiOAuth
*
service
.
OpenAIOAuthService
,
geminiOAuth
*
service
.
GeminiOAuthService
,
geminiOAuth
*
service
.
GeminiOAuthService
,
antigravityOAuth
*
service
.
AntigravityOAuthService
,
antigravityOAuth
*
service
.
AntigravityOAuthService
,
openAIGateway
*
service
.
OpenAIGatewayService
,
)
func
()
{
)
func
()
{
return
func
()
{
return
func
()
{
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
defer
cancel
()
// Cleanup steps in reverse dependency order
type
cleanupStep
struct
{
cleanupSteps
:=
[]
struct
{
name
string
name
string
fn
func
()
error
fn
func
()
error
}{
}
// 应用层清理步骤可并行执行,基础设施资源(Redis/Ent)最后按顺序关闭。
parallelSteps
:=
[]
cleanupStep
{
{
"OpsScheduledReportService"
,
func
()
error
{
{
"OpsScheduledReportService"
,
func
()
error
{
if
opsScheduledReport
!=
nil
{
if
opsScheduledReport
!=
nil
{
opsScheduledReport
.
Stop
()
opsScheduledReport
.
Stop
()
...
@@ -101,6 +110,18 @@ func provideCleanup(
...
@@ -101,6 +110,18 @@ func provideCleanup(
}
}
return
nil
return
nil
}},
}},
{
"OpsSystemLogSink"
,
func
()
error
{
if
opsSystemLogSink
!=
nil
{
opsSystemLogSink
.
Stop
()
}
return
nil
}},
{
"SoraMediaCleanupService"
,
func
()
error
{
if
soraMediaCleanup
!=
nil
{
soraMediaCleanup
.
Stop
()
}
return
nil
}},
{
"OpsAlertEvaluatorService"
,
func
()
error
{
{
"OpsAlertEvaluatorService"
,
func
()
error
{
if
opsAlertEvaluator
!=
nil
{
if
opsAlertEvaluator
!=
nil
{
opsAlertEvaluator
.
Stop
()
opsAlertEvaluator
.
Stop
()
...
@@ -131,6 +152,12 @@ func provideCleanup(
...
@@ -131,6 +152,12 @@ func provideCleanup(
}
}
return
nil
return
nil
}},
}},
{
"IdempotencyCleanupService"
,
func
()
error
{
if
idempotencyCleanup
!=
nil
{
idempotencyCleanup
.
Stop
()
}
return
nil
}},
{
"TokenRefreshService"
,
func
()
error
{
{
"TokenRefreshService"
,
func
()
error
{
tokenRefresh
.
Stop
()
tokenRefresh
.
Stop
()
return
nil
return
nil
...
@@ -143,6 +170,12 @@ func provideCleanup(
...
@@ -143,6 +170,12 @@ func provideCleanup(
subscriptionExpiry
.
Stop
()
subscriptionExpiry
.
Stop
()
return
nil
return
nil
}},
}},
{
"SubscriptionService"
,
func
()
error
{
if
subscriptionService
!=
nil
{
subscriptionService
.
Stop
()
}
return
nil
}},
{
"PricingService"
,
func
()
error
{
{
"PricingService"
,
func
()
error
{
pricing
.
Stop
()
pricing
.
Stop
()
return
nil
return
nil
...
@@ -155,6 +188,12 @@ func provideCleanup(
...
@@ -155,6 +188,12 @@ func provideCleanup(
billingCache
.
Stop
()
billingCache
.
Stop
()
return
nil
return
nil
}},
}},
{
"UsageRecordWorkerPool"
,
func
()
error
{
if
usageRecordWorkerPool
!=
nil
{
usageRecordWorkerPool
.
Stop
()
}
return
nil
}},
{
"OAuthService"
,
func
()
error
{
{
"OAuthService"
,
func
()
error
{
oauth
.
Stop
()
oauth
.
Stop
()
return
nil
return
nil
...
@@ -171,23 +210,60 @@ func provideCleanup(
...
@@ -171,23 +210,60 @@ func provideCleanup(
antigravityOAuth
.
Stop
()
antigravityOAuth
.
Stop
()
return
nil
return
nil
}},
}},
{
"OpenAIWSPool"
,
func
()
error
{
if
openAIGateway
!=
nil
{
openAIGateway
.
CloseOpenAIWSPool
()
}
return
nil
}},
}
infraSteps
:=
[]
cleanupStep
{
{
"Redis"
,
func
()
error
{
{
"Redis"
,
func
()
error
{
if
rdb
==
nil
{
return
nil
}
return
rdb
.
Close
()
return
rdb
.
Close
()
}},
}},
{
"Ent"
,
func
()
error
{
{
"Ent"
,
func
()
error
{
if
entClient
==
nil
{
return
nil
}
return
entClient
.
Close
()
return
entClient
.
Close
()
}},
}},
}
}
for
_
,
step
:=
range
cleanupSteps
{
runParallel
:=
func
(
steps
[]
cleanupStep
)
{
if
err
:=
step
.
fn
();
err
!=
nil
{
var
wg
sync
.
WaitGroup
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
for
i
:=
range
steps
{
// Continue with remaining cleanup steps even if one fails
step
:=
steps
[
i
]
}
else
{
wg
.
Add
(
1
)
go
func
()
{
defer
wg
.
Done
()
if
err
:=
step
.
fn
();
err
!=
nil
{
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
return
}
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
}()
}
wg
.
Wait
()
}
runSequential
:=
func
(
steps
[]
cleanupStep
)
{
for
i
:=
range
steps
{
step
:=
steps
[
i
]
if
err
:=
step
.
fn
();
err
!=
nil
{
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
continue
}
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
}
}
}
}
runParallel
(
parallelSteps
)
runSequential
(
infraSteps
)
// Check if context timed out
// Check if context timed out
select
{
select
{
case
<-
ctx
.
Done
()
:
case
<-
ctx
.
Done
()
:
...
...
backend/cmd/server/wire_gen.go
View file @
3d79773b
...
@@ -19,6 +19,7 @@ import (
...
@@ -19,6 +19,7 @@ import (
"github.com/redis/go-redis/v9"
"github.com/redis/go-redis/v9"
"log"
"log"
"net/http"
"net/http"
"sync"
"time"
"time"
)
)
...
@@ -47,7 +48,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -47,7 +48,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
redisClient
:=
repository
.
ProvideRedis
(
configConfig
)
redisClient
:=
repository
.
ProvideRedis
(
configConfig
)
refreshTokenCache
:=
repository
.
NewRefreshTokenCache
(
redisClient
)
refreshTokenCache
:=
repository
.
NewRefreshTokenCache
(
redisClient
)
settingRepository
:=
repository
.
NewSettingRepository
(
client
)
settingRepository
:=
repository
.
NewSettingRepository
(
client
)
settingService
:=
service
.
NewSettingService
(
settingRepository
,
configConfig
)
groupRepository
:=
repository
.
NewGroupRepository
(
client
,
db
)
settingService
:=
service
.
ProvideSettingService
(
settingRepository
,
groupRepository
,
configConfig
)
emailCache
:=
repository
.
NewEmailCache
(
redisClient
)
emailCache
:=
repository
.
NewEmailCache
(
redisClient
)
emailService
:=
service
.
NewEmailService
(
settingRepository
,
emailCache
)
emailService
:=
service
.
NewEmailService
(
settingRepository
,
emailCache
)
turnstileVerifier
:=
repository
.
NewTurnstileVerifier
()
turnstileVerifier
:=
repository
.
NewTurnstileVerifier
()
...
@@ -56,17 +58,17 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -56,17 +58,17 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
promoCodeRepository
:=
repository
.
NewPromoCodeRepository
(
client
)
promoCodeRepository
:=
repository
.
NewPromoCodeRepository
(
client
)
billingCache
:=
repository
.
NewBillingCache
(
redisClient
)
billingCache
:=
repository
.
NewBillingCache
(
redisClient
)
userSubscriptionRepository
:=
repository
.
NewUserSubscriptionRepository
(
client
)
userSubscriptionRepository
:=
repository
.
NewUserSubscriptionRepository
(
client
)
billingCacheService
:=
service
.
NewBillingCacheService
(
billingCache
,
userRepository
,
userSubscriptionRepository
,
configConfig
)
apiKeyRepository
:=
repository
.
NewAPIKeyRepository
(
client
,
db
)
apiKeyRepository
:=
repository
.
NewAPIKeyRepository
(
client
)
billingCacheService
:=
service
.
NewBillingCacheService
(
billingCache
,
userRepository
,
userSubscriptionRepository
,
apiKeyRepository
,
configConfig
)
groupRepository
:=
repository
.
NewGroupRepository
(
client
,
db
)
userGroupRateRepository
:=
repository
.
NewUserGroupRateRepository
(
db
)
userGroupRateRepository
:=
repository
.
NewUserGroupRateRepository
(
db
)
apiKeyCache
:=
repository
.
NewAPIKeyCache
(
redisClient
)
apiKeyCache
:=
repository
.
NewAPIKeyCache
(
redisClient
)
apiKeyService
:=
service
.
NewAPIKeyService
(
apiKeyRepository
,
userRepository
,
groupRepository
,
userSubscriptionRepository
,
userGroupRateRepository
,
apiKeyCache
,
configConfig
)
apiKeyService
:=
service
.
NewAPIKeyService
(
apiKeyRepository
,
userRepository
,
groupRepository
,
userSubscriptionRepository
,
userGroupRateRepository
,
apiKeyCache
,
configConfig
)
apiKeyService
.
SetRateLimitCacheInvalidator
(
billingCache
)
apiKeyAuthCacheInvalidator
:=
service
.
ProvideAPIKeyAuthCacheInvalidator
(
apiKeyService
)
apiKeyAuthCacheInvalidator
:=
service
.
ProvideAPIKeyAuthCacheInvalidator
(
apiKeyService
)
promoService
:=
service
.
NewPromoService
(
promoCodeRepository
,
userRepository
,
billingCacheService
,
client
,
apiKeyAuthCacheInvalidator
)
promoService
:=
service
.
NewPromoService
(
promoCodeRepository
,
userRepository
,
billingCacheService
,
client
,
apiKeyAuthCacheInvalidator
)
auth
Service
:=
service
.
New
Auth
Service
(
user
Repository
,
redeemCodeRepository
,
refreshTokenCache
,
configConfig
,
settingService
,
emailService
,
turnstileService
,
emailQueueService
,
promoService
)
subscription
Service
:=
service
.
New
Subscription
Service
(
group
Repository
,
userSubscriptionRepository
,
billingCacheService
,
client
,
configConfig
)
user
Service
:=
service
.
New
User
Service
(
userRepository
,
apiKeyAuthCacheInvalidator
)
auth
Service
:=
service
.
New
Auth
Service
(
userRepository
,
redeemCodeRepository
,
refreshTokenCache
,
configConfig
,
settingService
,
emailService
,
turnstileService
,
emailQueueService
,
promoService
,
subscriptionService
)
subscription
Service
:=
service
.
New
Subscription
Service
(
group
Repository
,
userSubscriptionReposi
tor
y
,
billingCache
Service
)
user
Service
:=
service
.
New
User
Service
(
user
Repository
,
apiKeyAuthCacheInvalida
tor
,
billingCache
)
redeemCache
:=
repository
.
NewRedeemCache
(
redisClient
)
redeemCache
:=
repository
.
NewRedeemCache
(
redisClient
)
redeemService
:=
service
.
NewRedeemService
(
redeemCodeRepository
,
userRepository
,
subscriptionService
,
redeemCache
,
billingCacheService
,
client
,
apiKeyAuthCacheInvalidator
)
redeemService
:=
service
.
NewRedeemService
(
redeemCodeRepository
,
userRepository
,
subscriptionService
,
redeemCache
,
billingCacheService
,
client
,
apiKeyAuthCacheInvalidator
)
secretEncryptor
,
err
:=
repository
.
NewAESEncryptor
(
configConfig
)
secretEncryptor
,
err
:=
repository
.
NewAESEncryptor
(
configConfig
)
...
@@ -98,10 +100,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -98,10 +100,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
dashboardHandler
:=
admin
.
NewDashboardHandler
(
dashboardService
,
dashboardAggregationService
)
dashboardHandler
:=
admin
.
NewDashboardHandler
(
dashboardService
,
dashboardAggregationService
)
schedulerCache
:=
repository
.
NewSchedulerCache
(
redisClient
)
schedulerCache
:=
repository
.
NewSchedulerCache
(
redisClient
)
accountRepository
:=
repository
.
NewAccountRepository
(
client
,
db
,
schedulerCache
)
accountRepository
:=
repository
.
NewAccountRepository
(
client
,
db
,
schedulerCache
)
soraAccountRepository
:=
repository
.
NewSoraAccountRepository
(
db
)
proxyRepository
:=
repository
.
NewProxyRepository
(
client
,
db
)
proxyRepository
:=
repository
.
NewProxyRepository
(
client
,
db
)
proxyExitInfoProber
:=
repository
.
NewProxyExitInfoProber
(
configConfig
)
proxyExitInfoProber
:=
repository
.
NewProxyExitInfoProber
(
configConfig
)
proxyLatencyCache
:=
repository
.
NewProxyLatencyCache
(
redisClient
)
proxyLatencyCache
:=
repository
.
NewProxyLatencyCache
(
redisClient
)
adminService
:=
service
.
NewAdminService
(
userRepository
,
groupRepository
,
accountRepository
,
proxyRepository
,
apiKeyRepository
,
redeemCodeRepository
,
userGroupRateRepository
,
billingCacheService
,
proxyExitInfoProber
,
proxyLatencyCache
,
apiKeyAuthCacheInvalidator
)
adminService
:=
service
.
NewAdminService
(
userRepository
,
groupRepository
,
accountRepository
,
soraAccountRepository
,
proxyRepository
,
apiKeyRepository
,
redeemCodeRepository
,
userGroupRateRepository
,
billingCacheService
,
proxyExitInfoProber
,
proxyLatencyCache
,
apiKeyAuthCacheInvalidator
,
client
,
settingService
,
subscriptionService
)
concurrencyCache
:=
repository
.
ProvideConcurrencyCache
(
redisClient
,
configConfig
)
concurrencyCache
:=
repository
.
ProvideConcurrencyCache
(
redisClient
,
configConfig
)
concurrencyService
:=
service
.
ProvideConcurrencyService
(
concurrencyCache
,
accountRepository
,
configConfig
)
concurrencyService
:=
service
.
ProvideConcurrencyService
(
concurrencyCache
,
accountRepository
,
configConfig
)
adminUserHandler
:=
admin
.
NewUserHandler
(
adminService
,
concurrencyService
)
adminUserHandler
:=
admin
.
NewUserHandler
(
adminService
,
concurrencyService
)
...
@@ -112,7 +115,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -112,7 +115,8 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
openAIOAuthService
:=
service
.
NewOpenAIOAuthService
(
proxyRepository
,
openAIOAuthClient
)
openAIOAuthService
:=
service
.
NewOpenAIOAuthService
(
proxyRepository
,
openAIOAuthClient
)
geminiOAuthClient
:=
repository
.
NewGeminiOAuthClient
(
configConfig
)
geminiOAuthClient
:=
repository
.
NewGeminiOAuthClient
(
configConfig
)
geminiCliCodeAssistClient
:=
repository
.
NewGeminiCliCodeAssistClient
()
geminiCliCodeAssistClient
:=
repository
.
NewGeminiCliCodeAssistClient
()
geminiOAuthService
:=
service
.
NewGeminiOAuthService
(
proxyRepository
,
geminiOAuthClient
,
geminiCliCodeAssistClient
,
configConfig
)
driveClient
:=
repository
.
NewGeminiDriveClient
()
geminiOAuthService
:=
service
.
NewGeminiOAuthService
(
proxyRepository
,
geminiOAuthClient
,
geminiCliCodeAssistClient
,
driveClient
,
configConfig
)
antigravityOAuthService
:=
service
.
NewAntigravityOAuthService
(
proxyRepository
)
antigravityOAuthService
:=
service
.
NewAntigravityOAuthService
(
proxyRepository
)
geminiQuotaService
:=
service
.
NewGeminiQuotaService
(
configConfig
,
settingRepository
)
geminiQuotaService
:=
service
.
NewGeminiQuotaService
(
configConfig
,
settingRepository
)
tempUnschedCache
:=
repository
.
NewTempUnschedCache
(
redisClient
)
tempUnschedCache
:=
repository
.
NewTempUnschedCache
(
redisClient
)
...
@@ -135,14 +139,17 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -135,14 +139,17 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
accountTestService
:=
service
.
NewAccountTestService
(
accountRepository
,
geminiTokenProvider
,
antigravityGatewayService
,
httpUpstream
,
configConfig
)
accountTestService
:=
service
.
NewAccountTestService
(
accountRepository
,
geminiTokenProvider
,
antigravityGatewayService
,
httpUpstream
,
configConfig
)
crsSyncService
:=
service
.
NewCRSSyncService
(
accountRepository
,
proxyRepository
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
configConfig
)
crsSyncService
:=
service
.
NewCRSSyncService
(
accountRepository
,
proxyRepository
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
configConfig
)
sessionLimitCache
:=
repository
.
ProvideSessionLimitCache
(
redisClient
,
configConfig
)
sessionLimitCache
:=
repository
.
ProvideSessionLimitCache
(
redisClient
,
configConfig
)
accountHandler
:=
admin
.
NewAccountHandler
(
adminService
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
,
rateLimitService
,
accountUsageService
,
accountTestService
,
concurrencyService
,
crsSyncService
,
sessionLimitCache
,
compositeTokenCacheInvalidator
)
rpmCache
:=
repository
.
NewRPMCache
(
redisClient
)
accountHandler
:=
admin
.
NewAccountHandler
(
adminService
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
,
rateLimitService
,
accountUsageService
,
accountTestService
,
concurrencyService
,
crsSyncService
,
sessionLimitCache
,
rpmCache
,
compositeTokenCacheInvalidator
)
adminAnnouncementHandler
:=
admin
.
NewAnnouncementHandler
(
announcementService
)
adminAnnouncementHandler
:=
admin
.
NewAnnouncementHandler
(
announcementService
)
dataManagementService
:=
service
.
NewDataManagementService
()
dataManagementHandler
:=
admin
.
NewDataManagementHandler
(
dataManagementService
)
oAuthHandler
:=
admin
.
NewOAuthHandler
(
oAuthService
)
oAuthHandler
:=
admin
.
NewOAuthHandler
(
oAuthService
)
openAIOAuthHandler
:=
admin
.
NewOpenAIOAuthHandler
(
openAIOAuthService
,
adminService
)
openAIOAuthHandler
:=
admin
.
NewOpenAIOAuthHandler
(
openAIOAuthService
,
adminService
)
geminiOAuthHandler
:=
admin
.
NewGeminiOAuthHandler
(
geminiOAuthService
)
geminiOAuthHandler
:=
admin
.
NewGeminiOAuthHandler
(
geminiOAuthService
)
antigravityOAuthHandler
:=
admin
.
NewAntigravityOAuthHandler
(
antigravityOAuthService
)
antigravityOAuthHandler
:=
admin
.
NewAntigravityOAuthHandler
(
antigravityOAuthService
)
proxyHandler
:=
admin
.
NewProxyHandler
(
adminService
)
proxyHandler
:=
admin
.
NewProxyHandler
(
adminService
)
adminRedeemHandler
:=
admin
.
NewRedeemHandler
(
adminService
)
adminRedeemHandler
:=
admin
.
NewRedeemHandler
(
adminService
,
redeemService
)
promoHandler
:=
admin
.
NewPromoHandler
(
promoService
)
promoHandler
:=
admin
.
NewPromoHandler
(
promoService
)
opsRepository
:=
repository
.
NewOpsRepository
(
db
)
opsRepository
:=
repository
.
NewOpsRepository
(
db
)
pricingRemoteClient
:=
repository
.
ProvidePricingRemoteClient
(
configConfig
)
pricingRemoteClient
:=
repository
.
ProvidePricingRemoteClient
(
configConfig
)
...
@@ -155,18 +162,26 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -155,18 +162,26 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
deferredService
:=
service
.
ProvideDeferredService
(
accountRepository
,
timingWheelService
)
deferredService
:=
service
.
ProvideDeferredService
(
accountRepository
,
timingWheelService
)
claudeTokenProvider
:=
service
.
NewClaudeTokenProvider
(
accountRepository
,
geminiTokenCache
,
oAuthService
)
claudeTokenProvider
:=
service
.
NewClaudeTokenProvider
(
accountRepository
,
geminiTokenCache
,
oAuthService
)
digestSessionStore
:=
service
.
NewDigestSessionStore
()
digestSessionStore
:=
service
.
NewDigestSessionStore
()
gatewayService
:=
service
.
NewGatewayService
(
accountRepository
,
groupRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
userGroupRateRepository
,
gatewayCache
,
configConfig
,
schedulerSnapshotService
,
concurrencyService
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
,
httpUpstream
,
deferredService
,
claudeTokenProvider
,
sessionLimitCache
,
digestSessionStore
)
gatewayService
:=
service
.
NewGatewayService
(
accountRepository
,
groupRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
userGroupRateRepository
,
gatewayCache
,
configConfig
,
schedulerSnapshotService
,
concurrencyService
,
billingService
,
rateLimitService
,
billingCacheService
,
identityService
,
httpUpstream
,
deferredService
,
claudeTokenProvider
,
sessionLimitCache
,
rpmCache
,
digestSessionStore
)
openAITokenProvider
:=
service
.
NewOpenAITokenProvider
(
accountRepository
,
geminiTokenCache
,
openAIOAuthService
)
openAITokenProvider
:=
service
.
NewOpenAITokenProvider
(
accountRepository
,
geminiTokenCache
,
openAIOAuthService
)
openAIGatewayService
:=
service
.
NewOpenAIGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
schedulerSnapshotService
,
concurrencyService
,
billingService
,
rateLimitService
,
billingCacheService
,
httpUpstream
,
deferredService
,
openAITokenProvider
)
openAIGatewayService
:=
service
.
NewOpenAIGatewayService
(
accountRepository
,
usageLogRepository
,
userRepository
,
userSubscriptionRepository
,
gatewayCache
,
configConfig
,
schedulerSnapshotService
,
concurrencyService
,
billingService
,
rateLimitService
,
billingCacheService
,
httpUpstream
,
deferredService
,
openAITokenProvider
)
geminiMessagesCompatService
:=
service
.
NewGeminiMessagesCompatService
(
accountRepository
,
groupRepository
,
gatewayCache
,
schedulerSnapshotService
,
geminiTokenProvider
,
rateLimitService
,
httpUpstream
,
antigravityGatewayService
,
configConfig
)
geminiMessagesCompatService
:=
service
.
NewGeminiMessagesCompatService
(
accountRepository
,
groupRepository
,
gatewayCache
,
schedulerSnapshotService
,
geminiTokenProvider
,
rateLimitService
,
httpUpstream
,
antigravityGatewayService
,
configConfig
)
opsService
:=
service
.
NewOpsService
(
opsRepository
,
settingRepository
,
configConfig
,
accountRepository
,
userRepository
,
concurrencyService
,
gatewayService
,
openAIGatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
)
opsSystemLogSink
:=
service
.
ProvideOpsSystemLogSink
(
opsRepository
)
settingHandler
:=
admin
.
NewSettingHandler
(
settingService
,
emailService
,
turnstileService
,
opsService
)
opsService
:=
service
.
NewOpsService
(
opsRepository
,
settingRepository
,
configConfig
,
accountRepository
,
userRepository
,
concurrencyService
,
gatewayService
,
openAIGatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
,
opsSystemLogSink
)
soraS3Storage
:=
service
.
NewSoraS3Storage
(
settingService
)
settingService
.
SetOnS3UpdateCallback
(
soraS3Storage
.
RefreshClient
)
soraGenerationRepository
:=
repository
.
NewSoraGenerationRepository
(
db
)
soraQuotaService
:=
service
.
NewSoraQuotaService
(
userRepository
,
groupRepository
,
settingService
)
soraGenerationService
:=
service
.
NewSoraGenerationService
(
soraGenerationRepository
,
soraS3Storage
,
soraQuotaService
)
settingHandler
:=
admin
.
NewSettingHandler
(
settingService
,
emailService
,
turnstileService
,
opsService
,
soraS3Storage
)
opsHandler
:=
admin
.
NewOpsHandler
(
opsService
)
opsHandler
:=
admin
.
NewOpsHandler
(
opsService
)
updateCache
:=
repository
.
NewUpdateCache
(
redisClient
)
updateCache
:=
repository
.
NewUpdateCache
(
redisClient
)
gitHubReleaseClient
:=
repository
.
ProvideGitHubReleaseClient
(
configConfig
)
gitHubReleaseClient
:=
repository
.
ProvideGitHubReleaseClient
(
configConfig
)
serviceBuildInfo
:=
provideServiceBuildInfo
(
buildInfo
)
serviceBuildInfo
:=
provideServiceBuildInfo
(
buildInfo
)
updateService
:=
service
.
ProvideUpdateService
(
updateCache
,
gitHubReleaseClient
,
serviceBuildInfo
)
updateService
:=
service
.
ProvideUpdateService
(
updateCache
,
gitHubReleaseClient
,
serviceBuildInfo
)
systemHandler
:=
handler
.
ProvideSystemHandler
(
updateService
)
idempotencyRepository
:=
repository
.
NewIdempotencyRepository
(
client
,
db
)
systemOperationLockService
:=
service
.
ProvideSystemOperationLockService
(
idempotencyRepository
,
configConfig
)
systemHandler
:=
handler
.
ProvideSystemHandler
(
updateService
,
systemOperationLockService
)
adminSubscriptionHandler
:=
admin
.
NewSubscriptionHandler
(
subscriptionService
)
adminSubscriptionHandler
:=
admin
.
NewSubscriptionHandler
(
subscriptionService
)
usageCleanupRepository
:=
repository
.
NewUsageCleanupRepository
(
client
,
db
)
usageCleanupRepository
:=
repository
.
NewUsageCleanupRepository
(
client
,
db
)
usageCleanupService
:=
service
.
ProvideUsageCleanupService
(
usageCleanupRepository
,
timingWheelService
,
dashboardAggregationService
,
configConfig
)
usageCleanupService
:=
service
.
ProvideUsageCleanupService
(
usageCleanupRepository
,
timingWheelService
,
dashboardAggregationService
,
configConfig
)
...
@@ -179,12 +194,23 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -179,12 +194,23 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
errorPassthroughCache
:=
repository
.
NewErrorPassthroughCache
(
redisClient
)
errorPassthroughCache
:=
repository
.
NewErrorPassthroughCache
(
redisClient
)
errorPassthroughService
:=
service
.
NewErrorPassthroughService
(
errorPassthroughRepository
,
errorPassthroughCache
)
errorPassthroughService
:=
service
.
NewErrorPassthroughService
(
errorPassthroughRepository
,
errorPassthroughCache
)
errorPassthroughHandler
:=
admin
.
NewErrorPassthroughHandler
(
errorPassthroughService
)
errorPassthroughHandler
:=
admin
.
NewErrorPassthroughHandler
(
errorPassthroughService
)
adminHandlers
:=
handler
.
ProvideAdminHandlers
(
dashboardHandler
,
adminUserHandler
,
groupHandler
,
accountHandler
,
adminAnnouncementHandler
,
oAuthHandler
,
openAIOAuthHandler
,
geminiOAuthHandler
,
antigravityOAuthHandler
,
proxyHandler
,
adminRedeemHandler
,
promoHandler
,
settingHandler
,
opsHandler
,
systemHandler
,
adminSubscriptionHandler
,
adminUsageHandler
,
userAttributeHandler
,
errorPassthroughHandler
)
adminAPIKeyHandler
:=
admin
.
NewAdminAPIKeyHandler
(
adminService
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
,
userService
,
concurrencyService
,
billingCacheService
,
usageService
,
apiKeyService
,
errorPassthroughService
,
configConfig
)
adminHandlers
:=
handler
.
ProvideAdminHandlers
(
dashboardHandler
,
adminUserHandler
,
groupHandler
,
accountHandler
,
adminAnnouncementHandler
,
dataManagementHandler
,
oAuthHandler
,
openAIOAuthHandler
,
geminiOAuthHandler
,
antigravityOAuthHandler
,
proxyHandler
,
adminRedeemHandler
,
promoHandler
,
settingHandler
,
opsHandler
,
systemHandler
,
adminSubscriptionHandler
,
adminUsageHandler
,
userAttributeHandler
,
errorPassthroughHandler
,
adminAPIKeyHandler
)
openAIGatewayHandler
:=
handler
.
NewOpenAIGatewayHandler
(
openAIGatewayService
,
concurrencyService
,
billingCacheService
,
apiKeyService
,
errorPassthroughService
,
configConfig
)
usageRecordWorkerPool
:=
service
.
NewUsageRecordWorkerPool
(
configConfig
)
userMsgQueueCache
:=
repository
.
NewUserMsgQueueCache
(
redisClient
)
userMessageQueueService
:=
service
.
ProvideUserMessageQueueService
(
userMsgQueueCache
,
rpmCache
,
configConfig
)
gatewayHandler
:=
handler
.
NewGatewayHandler
(
gatewayService
,
geminiMessagesCompatService
,
antigravityGatewayService
,
userService
,
concurrencyService
,
billingCacheService
,
usageService
,
apiKeyService
,
usageRecordWorkerPool
,
errorPassthroughService
,
userMessageQueueService
,
configConfig
,
settingService
)
openAIGatewayHandler
:=
handler
.
NewOpenAIGatewayHandler
(
openAIGatewayService
,
concurrencyService
,
billingCacheService
,
apiKeyService
,
usageRecordWorkerPool
,
errorPassthroughService
,
configConfig
)
soraSDKClient
:=
service
.
ProvideSoraSDKClient
(
configConfig
,
httpUpstream
,
openAITokenProvider
,
accountRepository
,
soraAccountRepository
)
soraMediaStorage
:=
service
.
ProvideSoraMediaStorage
(
configConfig
)
soraGatewayService
:=
service
.
NewSoraGatewayService
(
soraSDKClient
,
rateLimitService
,
httpUpstream
,
configConfig
)
soraClientHandler
:=
handler
.
NewSoraClientHandler
(
soraGenerationService
,
soraQuotaService
,
soraS3Storage
,
soraGatewayService
,
gatewayService
,
soraMediaStorage
,
apiKeyService
)
soraGatewayHandler
:=
handler
.
NewSoraGatewayHandler
(
gatewayService
,
soraGatewayService
,
concurrencyService
,
billingCacheService
,
usageRecordWorkerPool
,
configConfig
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
handlerSettingHandler
:=
handler
.
ProvideSettingHandler
(
settingService
,
buildInfo
)
totpHandler
:=
handler
.
NewTotpHandler
(
totpService
)
totpHandler
:=
handler
.
NewTotpHandler
(
totpService
)
handlers
:=
handler
.
ProvideHandlers
(
authHandler
,
userHandler
,
apiKeyHandler
,
usageHandler
,
redeemHandler
,
subscriptionHandler
,
announcementHandler
,
adminHandlers
,
gatewayHandler
,
openAIGatewayHandler
,
handlerSettingHandler
,
totpHandler
)
idempotencyCoordinator
:=
service
.
ProvideIdempotencyCoordinator
(
idempotencyRepository
,
configConfig
)
idempotencyCleanupService
:=
service
.
ProvideIdempotencyCleanupService
(
idempotencyRepository
,
configConfig
)
handlers
:=
handler
.
ProvideHandlers
(
authHandler
,
userHandler
,
apiKeyHandler
,
usageHandler
,
redeemHandler
,
subscriptionHandler
,
announcementHandler
,
adminHandlers
,
gatewayHandler
,
openAIGatewayHandler
,
soraGatewayHandler
,
soraClientHandler
,
handlerSettingHandler
,
totpHandler
,
idempotencyCoordinator
,
idempotencyCleanupService
)
jwtAuthMiddleware
:=
middleware
.
NewJWTAuthMiddleware
(
authService
,
userService
)
jwtAuthMiddleware
:=
middleware
.
NewJWTAuthMiddleware
(
authService
,
userService
)
adminAuthMiddleware
:=
middleware
.
NewAdminAuthMiddleware
(
authService
,
userService
,
settingService
)
adminAuthMiddleware
:=
middleware
.
NewAdminAuthMiddleware
(
authService
,
userService
,
settingService
)
apiKeyAuthMiddleware
:=
middleware
.
NewAPIKeyAuthMiddleware
(
apiKeyService
,
subscriptionService
,
configConfig
)
apiKeyAuthMiddleware
:=
middleware
.
NewAPIKeyAuthMiddleware
(
apiKeyService
,
subscriptionService
,
configConfig
)
...
@@ -195,10 +221,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
...
@@ -195,10 +221,11 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
opsAlertEvaluatorService
:=
service
.
ProvideOpsAlertEvaluatorService
(
opsService
,
opsRepository
,
emailService
,
redisClient
,
configConfig
)
opsAlertEvaluatorService
:=
service
.
ProvideOpsAlertEvaluatorService
(
opsService
,
opsRepository
,
emailService
,
redisClient
,
configConfig
)
opsCleanupService
:=
service
.
ProvideOpsCleanupService
(
opsRepository
,
db
,
redisClient
,
configConfig
)
opsCleanupService
:=
service
.
ProvideOpsCleanupService
(
opsRepository
,
db
,
redisClient
,
configConfig
)
opsScheduledReportService
:=
service
.
ProvideOpsScheduledReportService
(
opsService
,
userService
,
emailService
,
redisClient
,
configConfig
)
opsScheduledReportService
:=
service
.
ProvideOpsScheduledReportService
(
opsService
,
userService
,
emailService
,
redisClient
,
configConfig
)
tokenRefreshService
:=
service
.
ProvideTokenRefreshService
(
accountRepository
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
,
compositeTokenCacheInvalidator
,
schedulerCache
,
configConfig
)
soraMediaCleanupService
:=
service
.
ProvideSoraMediaCleanupService
(
soraMediaStorage
,
configConfig
)
tokenRefreshService
:=
service
.
ProvideTokenRefreshService
(
accountRepository
,
soraAccountRepository
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
,
compositeTokenCacheInvalidator
,
schedulerCache
,
configConfig
,
tempUnschedCache
)
accountExpiryService
:=
service
.
ProvideAccountExpiryService
(
accountRepository
)
accountExpiryService
:=
service
.
ProvideAccountExpiryService
(
accountRepository
)
subscriptionExpiryService
:=
service
.
ProvideSubscriptionExpiryService
(
userSubscriptionRepository
)
subscriptionExpiryService
:=
service
.
ProvideSubscriptionExpiryService
(
userSubscriptionRepository
)
v
:=
provideCleanup
(
client
,
redisClient
,
opsMetricsCollector
,
opsAggregationService
,
opsAlertEvaluatorService
,
opsCleanupService
,
opsScheduledReportService
,
schedulerSnapshotService
,
tokenRefreshService
,
accountExpiryService
,
subscriptionExpiryService
,
usageCleanupService
,
pricingService
,
emailQueueService
,
billingCacheService
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
)
v
:=
provideCleanup
(
client
,
redisClient
,
opsMetricsCollector
,
opsAggregationService
,
opsAlertEvaluatorService
,
opsCleanupService
,
opsScheduledReportService
,
opsSystemLogSink
,
soraMediaCleanupService
,
schedulerSnapshotService
,
tokenRefreshService
,
accountExpiryService
,
subscriptionExpiryService
,
usageCleanupService
,
idempotencyCleanupService
,
pricingService
,
emailQueueService
,
billingCacheService
,
usageRecordWorkerPool
,
subscriptionService
,
oAuthService
,
openAIOAuthService
,
geminiOAuthService
,
antigravityOAuthService
,
openAIGatewayService
)
application
:=
&
Application
{
application
:=
&
Application
{
Server
:
httpServer
,
Server
:
httpServer
,
Cleanup
:
v
,
Cleanup
:
v
,
...
@@ -228,27 +255,35 @@ func provideCleanup(
...
@@ -228,27 +255,35 @@ func provideCleanup(
opsAlertEvaluator
*
service
.
OpsAlertEvaluatorService
,
opsAlertEvaluator
*
service
.
OpsAlertEvaluatorService
,
opsCleanup
*
service
.
OpsCleanupService
,
opsCleanup
*
service
.
OpsCleanupService
,
opsScheduledReport
*
service
.
OpsScheduledReportService
,
opsScheduledReport
*
service
.
OpsScheduledReportService
,
opsSystemLogSink
*
service
.
OpsSystemLogSink
,
soraMediaCleanup
*
service
.
SoraMediaCleanupService
,
schedulerSnapshot
*
service
.
SchedulerSnapshotService
,
schedulerSnapshot
*
service
.
SchedulerSnapshotService
,
tokenRefresh
*
service
.
TokenRefreshService
,
tokenRefresh
*
service
.
TokenRefreshService
,
accountExpiry
*
service
.
AccountExpiryService
,
accountExpiry
*
service
.
AccountExpiryService
,
subscriptionExpiry
*
service
.
SubscriptionExpiryService
,
subscriptionExpiry
*
service
.
SubscriptionExpiryService
,
usageCleanup
*
service
.
UsageCleanupService
,
usageCleanup
*
service
.
UsageCleanupService
,
idempotencyCleanup
*
service
.
IdempotencyCleanupService
,
pricing
*
service
.
PricingService
,
pricing
*
service
.
PricingService
,
emailQueue
*
service
.
EmailQueueService
,
emailQueue
*
service
.
EmailQueueService
,
billingCache
*
service
.
BillingCacheService
,
billingCache
*
service
.
BillingCacheService
,
usageRecordWorkerPool
*
service
.
UsageRecordWorkerPool
,
subscriptionService
*
service
.
SubscriptionService
,
oauth
*
service
.
OAuthService
,
oauth
*
service
.
OAuthService
,
openaiOAuth
*
service
.
OpenAIOAuthService
,
openaiOAuth
*
service
.
OpenAIOAuthService
,
geminiOAuth
*
service
.
GeminiOAuthService
,
geminiOAuth
*
service
.
GeminiOAuthService
,
antigravityOAuth
*
service
.
AntigravityOAuthService
,
antigravityOAuth
*
service
.
AntigravityOAuthService
,
openAIGateway
*
service
.
OpenAIGatewayService
,
)
func
()
{
)
func
()
{
return
func
()
{
return
func
()
{
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
10
*
time
.
Second
)
defer
cancel
()
defer
cancel
()
cleanupStep
s
:=
[]
struct
{
type
cleanupStep
struct
{
name
string
name
string
fn
func
()
error
fn
func
()
error
}{
}
parallelSteps
:=
[]
cleanupStep
{
{
"OpsScheduledReportService"
,
func
()
error
{
{
"OpsScheduledReportService"
,
func
()
error
{
if
opsScheduledReport
!=
nil
{
if
opsScheduledReport
!=
nil
{
opsScheduledReport
.
Stop
()
opsScheduledReport
.
Stop
()
...
@@ -261,6 +296,18 @@ func provideCleanup(
...
@@ -261,6 +296,18 @@ func provideCleanup(
}
}
return
nil
return
nil
}},
}},
{
"OpsSystemLogSink"
,
func
()
error
{
if
opsSystemLogSink
!=
nil
{
opsSystemLogSink
.
Stop
()
}
return
nil
}},
{
"SoraMediaCleanupService"
,
func
()
error
{
if
soraMediaCleanup
!=
nil
{
soraMediaCleanup
.
Stop
()
}
return
nil
}},
{
"OpsAlertEvaluatorService"
,
func
()
error
{
{
"OpsAlertEvaluatorService"
,
func
()
error
{
if
opsAlertEvaluator
!=
nil
{
if
opsAlertEvaluator
!=
nil
{
opsAlertEvaluator
.
Stop
()
opsAlertEvaluator
.
Stop
()
...
@@ -291,6 +338,12 @@ func provideCleanup(
...
@@ -291,6 +338,12 @@ func provideCleanup(
}
}
return
nil
return
nil
}},
}},
{
"IdempotencyCleanupService"
,
func
()
error
{
if
idempotencyCleanup
!=
nil
{
idempotencyCleanup
.
Stop
()
}
return
nil
}},
{
"TokenRefreshService"
,
func
()
error
{
{
"TokenRefreshService"
,
func
()
error
{
tokenRefresh
.
Stop
()
tokenRefresh
.
Stop
()
return
nil
return
nil
...
@@ -303,6 +356,12 @@ func provideCleanup(
...
@@ -303,6 +356,12 @@ func provideCleanup(
subscriptionExpiry
.
Stop
()
subscriptionExpiry
.
Stop
()
return
nil
return
nil
}},
}},
{
"SubscriptionService"
,
func
()
error
{
if
subscriptionService
!=
nil
{
subscriptionService
.
Stop
()
}
return
nil
}},
{
"PricingService"
,
func
()
error
{
{
"PricingService"
,
func
()
error
{
pricing
.
Stop
()
pricing
.
Stop
()
return
nil
return
nil
...
@@ -315,6 +374,12 @@ func provideCleanup(
...
@@ -315,6 +374,12 @@ func provideCleanup(
billingCache
.
Stop
()
billingCache
.
Stop
()
return
nil
return
nil
}},
}},
{
"UsageRecordWorkerPool"
,
func
()
error
{
if
usageRecordWorkerPool
!=
nil
{
usageRecordWorkerPool
.
Stop
()
}
return
nil
}},
{
"OAuthService"
,
func
()
error
{
{
"OAuthService"
,
func
()
error
{
oauth
.
Stop
()
oauth
.
Stop
()
return
nil
return
nil
...
@@ -331,23 +396,60 @@ func provideCleanup(
...
@@ -331,23 +396,60 @@ func provideCleanup(
antigravityOAuth
.
Stop
()
antigravityOAuth
.
Stop
()
return
nil
return
nil
}},
}},
{
"OpenAIWSPool"
,
func
()
error
{
if
openAIGateway
!=
nil
{
openAIGateway
.
CloseOpenAIWSPool
()
}
return
nil
}},
}
infraSteps
:=
[]
cleanupStep
{
{
"Redis"
,
func
()
error
{
{
"Redis"
,
func
()
error
{
if
rdb
==
nil
{
return
nil
}
return
rdb
.
Close
()
return
rdb
.
Close
()
}},
}},
{
"Ent"
,
func
()
error
{
{
"Ent"
,
func
()
error
{
if
entClient
==
nil
{
return
nil
}
return
entClient
.
Close
()
return
entClient
.
Close
()
}},
}},
}
}
for
_
,
step
:=
range
cleanupSteps
{
runParallel
:=
func
(
steps
[]
cleanupStep
)
{
if
err
:=
step
.
fn
();
err
!=
nil
{
var
wg
sync
.
WaitGroup
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
for
i
:=
range
steps
{
step
:=
steps
[
i
]
wg
.
Add
(
1
)
go
func
()
{
defer
wg
.
Done
()
if
err
:=
step
.
fn
();
err
!=
nil
{
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
return
}
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
}()
}
wg
.
Wait
()
}
}
else
{
runSequential
:=
func
(
steps
[]
cleanupStep
)
{
for
i
:=
range
steps
{
step
:=
steps
[
i
]
if
err
:=
step
.
fn
();
err
!=
nil
{
log
.
Printf
(
"[Cleanup] %s failed: %v"
,
step
.
name
,
err
)
continue
}
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
log
.
Printf
(
"[Cleanup] %s succeeded"
,
step
.
name
)
}
}
}
}
runParallel
(
parallelSteps
)
runSequential
(
infraSteps
)
select
{
select
{
case
<-
ctx
.
Done
()
:
case
<-
ctx
.
Done
()
:
log
.
Printf
(
"[Cleanup] Warning: cleanup timed out after 10 seconds"
)
log
.
Printf
(
"[Cleanup] Warning: cleanup timed out after 10 seconds"
)
...
...
backend/cmd/server/wire_gen_test.go
0 → 100644
View file @
3d79773b
package
main
import
(
"testing"
"time"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/handler"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/stretchr/testify/require"
)
func
TestProvideServiceBuildInfo
(
t
*
testing
.
T
)
{
in
:=
handler
.
BuildInfo
{
Version
:
"v-test"
,
BuildType
:
"release"
,
}
out
:=
provideServiceBuildInfo
(
in
)
require
.
Equal
(
t
,
in
.
Version
,
out
.
Version
)
require
.
Equal
(
t
,
in
.
BuildType
,
out
.
BuildType
)
}
func
TestProvideCleanup_WithMinimalDependencies_NoPanic
(
t
*
testing
.
T
)
{
cfg
:=
&
config
.
Config
{}
oauthSvc
:=
service
.
NewOAuthService
(
nil
,
nil
)
openAIOAuthSvc
:=
service
.
NewOpenAIOAuthService
(
nil
,
nil
)
geminiOAuthSvc
:=
service
.
NewGeminiOAuthService
(
nil
,
nil
,
nil
,
nil
,
cfg
)
antigravityOAuthSvc
:=
service
.
NewAntigravityOAuthService
(
nil
)
tokenRefreshSvc
:=
service
.
NewTokenRefreshService
(
nil
,
oauthSvc
,
openAIOAuthSvc
,
geminiOAuthSvc
,
antigravityOAuthSvc
,
nil
,
nil
,
cfg
,
nil
,
)
accountExpirySvc
:=
service
.
NewAccountExpiryService
(
nil
,
time
.
Second
)
subscriptionExpirySvc
:=
service
.
NewSubscriptionExpiryService
(
nil
,
time
.
Second
)
pricingSvc
:=
service
.
NewPricingService
(
cfg
,
nil
)
emailQueueSvc
:=
service
.
NewEmailQueueService
(
nil
,
1
)
billingCacheSvc
:=
service
.
NewBillingCacheService
(
nil
,
nil
,
nil
,
nil
,
cfg
)
idempotencyCleanupSvc
:=
service
.
NewIdempotencyCleanupService
(
nil
,
cfg
)
schedulerSnapshotSvc
:=
service
.
NewSchedulerSnapshotService
(
nil
,
nil
,
nil
,
nil
,
cfg
)
opsSystemLogSinkSvc
:=
service
.
NewOpsSystemLogSink
(
nil
)
cleanup
:=
provideCleanup
(
nil
,
// entClient
nil
,
// redis
&
service
.
OpsMetricsCollector
{},
&
service
.
OpsAggregationService
{},
&
service
.
OpsAlertEvaluatorService
{},
&
service
.
OpsCleanupService
{},
&
service
.
OpsScheduledReportService
{},
opsSystemLogSinkSvc
,
&
service
.
SoraMediaCleanupService
{},
schedulerSnapshotSvc
,
tokenRefreshSvc
,
accountExpirySvc
,
subscriptionExpirySvc
,
&
service
.
UsageCleanupService
{},
idempotencyCleanupSvc
,
pricingSvc
,
emailQueueSvc
,
billingCacheSvc
,
&
service
.
UsageRecordWorkerPool
{},
&
service
.
SubscriptionService
{},
oauthSvc
,
openAIOAuthSvc
,
geminiOAuthSvc
,
antigravityOAuthSvc
,
nil
,
// openAIGateway
)
require
.
NotPanics
(
t
,
func
()
{
cleanup
()
})
}
backend/ent/account.go
View file @
3d79773b
...
@@ -63,6 +63,10 @@ type Account struct {
...
@@ -63,6 +63,10 @@ type Account struct {
RateLimitResetAt
*
time
.
Time
`json:"rate_limit_reset_at,omitempty"`
RateLimitResetAt
*
time
.
Time
`json:"rate_limit_reset_at,omitempty"`
// OverloadUntil holds the value of the "overload_until" field.
// OverloadUntil holds the value of the "overload_until" field.
OverloadUntil
*
time
.
Time
`json:"overload_until,omitempty"`
OverloadUntil
*
time
.
Time
`json:"overload_until,omitempty"`
// TempUnschedulableUntil holds the value of the "temp_unschedulable_until" field.
TempUnschedulableUntil
*
time
.
Time
`json:"temp_unschedulable_until,omitempty"`
// TempUnschedulableReason holds the value of the "temp_unschedulable_reason" field.
TempUnschedulableReason
*
string
`json:"temp_unschedulable_reason,omitempty"`
// SessionWindowStart holds the value of the "session_window_start" field.
// SessionWindowStart holds the value of the "session_window_start" field.
SessionWindowStart
*
time
.
Time
`json:"session_window_start,omitempty"`
SessionWindowStart
*
time
.
Time
`json:"session_window_start,omitempty"`
// SessionWindowEnd holds the value of the "session_window_end" field.
// SessionWindowEnd holds the value of the "session_window_end" field.
...
@@ -141,9 +145,9 @@ func (*Account) scanValues(columns []string) ([]any, error) {
...
@@ -141,9 +145,9 @@ func (*Account) scanValues(columns []string) ([]any, error) {
values
[
i
]
=
new
(
sql
.
NullFloat64
)
values
[
i
]
=
new
(
sql
.
NullFloat64
)
case
account
.
FieldID
,
account
.
FieldProxyID
,
account
.
FieldConcurrency
,
account
.
FieldPriority
:
case
account
.
FieldID
,
account
.
FieldProxyID
,
account
.
FieldConcurrency
,
account
.
FieldPriority
:
values
[
i
]
=
new
(
sql
.
NullInt64
)
values
[
i
]
=
new
(
sql
.
NullInt64
)
case
account
.
FieldName
,
account
.
FieldNotes
,
account
.
FieldPlatform
,
account
.
FieldType
,
account
.
FieldStatus
,
account
.
FieldErrorMessage
,
account
.
FieldSessionWindowStatus
:
case
account
.
FieldName
,
account
.
FieldNotes
,
account
.
FieldPlatform
,
account
.
FieldType
,
account
.
FieldStatus
,
account
.
FieldErrorMessage
,
account
.
FieldTempUnschedulableReason
,
account
.
FieldSessionWindowStatus
:
values
[
i
]
=
new
(
sql
.
NullString
)
values
[
i
]
=
new
(
sql
.
NullString
)
case
account
.
FieldCreatedAt
,
account
.
FieldUpdatedAt
,
account
.
FieldDeletedAt
,
account
.
FieldLastUsedAt
,
account
.
FieldExpiresAt
,
account
.
FieldRateLimitedAt
,
account
.
FieldRateLimitResetAt
,
account
.
FieldOverloadUntil
,
account
.
FieldSessionWindowStart
,
account
.
FieldSessionWindowEnd
:
case
account
.
FieldCreatedAt
,
account
.
FieldUpdatedAt
,
account
.
FieldDeletedAt
,
account
.
FieldLastUsedAt
,
account
.
FieldExpiresAt
,
account
.
FieldRateLimitedAt
,
account
.
FieldRateLimitResetAt
,
account
.
FieldOverloadUntil
,
account
.
FieldTempUnschedulableUntil
,
account
.
FieldSessionWindowStart
,
account
.
FieldSessionWindowEnd
:
values
[
i
]
=
new
(
sql
.
NullTime
)
values
[
i
]
=
new
(
sql
.
NullTime
)
default
:
default
:
values
[
i
]
=
new
(
sql
.
UnknownType
)
values
[
i
]
=
new
(
sql
.
UnknownType
)
...
@@ -311,6 +315,20 @@ func (_m *Account) assignValues(columns []string, values []any) error {
...
@@ -311,6 +315,20 @@ func (_m *Account) assignValues(columns []string, values []any) error {
_m
.
OverloadUntil
=
new
(
time
.
Time
)
_m
.
OverloadUntil
=
new
(
time
.
Time
)
*
_m
.
OverloadUntil
=
value
.
Time
*
_m
.
OverloadUntil
=
value
.
Time
}
}
case
account
.
FieldTempUnschedulableUntil
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullTime
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field temp_unschedulable_until"
,
values
[
i
])
}
else
if
value
.
Valid
{
_m
.
TempUnschedulableUntil
=
new
(
time
.
Time
)
*
_m
.
TempUnschedulableUntil
=
value
.
Time
}
case
account
.
FieldTempUnschedulableReason
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullString
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field temp_unschedulable_reason"
,
values
[
i
])
}
else
if
value
.
Valid
{
_m
.
TempUnschedulableReason
=
new
(
string
)
*
_m
.
TempUnschedulableReason
=
value
.
String
}
case
account
.
FieldSessionWindowStart
:
case
account
.
FieldSessionWindowStart
:
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullTime
);
!
ok
{
if
value
,
ok
:=
values
[
i
]
.
(
*
sql
.
NullTime
);
!
ok
{
return
fmt
.
Errorf
(
"unexpected type %T for field session_window_start"
,
values
[
i
])
return
fmt
.
Errorf
(
"unexpected type %T for field session_window_start"
,
values
[
i
])
...
@@ -472,6 +490,16 @@ func (_m *Account) String() string {
...
@@ -472,6 +490,16 @@ func (_m *Account) String() string {
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
}
}
builder
.
WriteString
(
", "
)
builder
.
WriteString
(
", "
)
if
v
:=
_m
.
TempUnschedulableUntil
;
v
!=
nil
{
builder
.
WriteString
(
"temp_unschedulable_until="
)
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
}
builder
.
WriteString
(
", "
)
if
v
:=
_m
.
TempUnschedulableReason
;
v
!=
nil
{
builder
.
WriteString
(
"temp_unschedulable_reason="
)
builder
.
WriteString
(
*
v
)
}
builder
.
WriteString
(
", "
)
if
v
:=
_m
.
SessionWindowStart
;
v
!=
nil
{
if
v
:=
_m
.
SessionWindowStart
;
v
!=
nil
{
builder
.
WriteString
(
"session_window_start="
)
builder
.
WriteString
(
"session_window_start="
)
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
builder
.
WriteString
(
v
.
Format
(
time
.
ANSIC
))
...
...
backend/ent/account/account.go
View file @
3d79773b
...
@@ -59,6 +59,10 @@ const (
...
@@ -59,6 +59,10 @@ const (
FieldRateLimitResetAt
=
"rate_limit_reset_at"
FieldRateLimitResetAt
=
"rate_limit_reset_at"
// FieldOverloadUntil holds the string denoting the overload_until field in the database.
// FieldOverloadUntil holds the string denoting the overload_until field in the database.
FieldOverloadUntil
=
"overload_until"
FieldOverloadUntil
=
"overload_until"
// FieldTempUnschedulableUntil holds the string denoting the temp_unschedulable_until field in the database.
FieldTempUnschedulableUntil
=
"temp_unschedulable_until"
// FieldTempUnschedulableReason holds the string denoting the temp_unschedulable_reason field in the database.
FieldTempUnschedulableReason
=
"temp_unschedulable_reason"
// FieldSessionWindowStart holds the string denoting the session_window_start field in the database.
// FieldSessionWindowStart holds the string denoting the session_window_start field in the database.
FieldSessionWindowStart
=
"session_window_start"
FieldSessionWindowStart
=
"session_window_start"
// FieldSessionWindowEnd holds the string denoting the session_window_end field in the database.
// FieldSessionWindowEnd holds the string denoting the session_window_end field in the database.
...
@@ -128,6 +132,8 @@ var Columns = []string{
...
@@ -128,6 +132,8 @@ var Columns = []string{
FieldRateLimitedAt
,
FieldRateLimitedAt
,
FieldRateLimitResetAt
,
FieldRateLimitResetAt
,
FieldOverloadUntil
,
FieldOverloadUntil
,
FieldTempUnschedulableUntil
,
FieldTempUnschedulableReason
,
FieldSessionWindowStart
,
FieldSessionWindowStart
,
FieldSessionWindowEnd
,
FieldSessionWindowEnd
,
FieldSessionWindowStatus
,
FieldSessionWindowStatus
,
...
@@ -299,6 +305,16 @@ func ByOverloadUntil(opts ...sql.OrderTermOption) OrderOption {
...
@@ -299,6 +305,16 @@ func ByOverloadUntil(opts ...sql.OrderTermOption) OrderOption {
return
sql
.
OrderByField
(
FieldOverloadUntil
,
opts
...
)
.
ToFunc
()
return
sql
.
OrderByField
(
FieldOverloadUntil
,
opts
...
)
.
ToFunc
()
}
}
// ByTempUnschedulableUntil orders the results by the temp_unschedulable_until field.
func
ByTempUnschedulableUntil
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldTempUnschedulableUntil
,
opts
...
)
.
ToFunc
()
}
// ByTempUnschedulableReason orders the results by the temp_unschedulable_reason field.
func
ByTempUnschedulableReason
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldTempUnschedulableReason
,
opts
...
)
.
ToFunc
()
}
// BySessionWindowStart orders the results by the session_window_start field.
// BySessionWindowStart orders the results by the session_window_start field.
func
BySessionWindowStart
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
func
BySessionWindowStart
(
opts
...
sql
.
OrderTermOption
)
OrderOption
{
return
sql
.
OrderByField
(
FieldSessionWindowStart
,
opts
...
)
.
ToFunc
()
return
sql
.
OrderByField
(
FieldSessionWindowStart
,
opts
...
)
.
ToFunc
()
...
...
backend/ent/account/where.go
View file @
3d79773b
...
@@ -155,6 +155,16 @@ func OverloadUntil(v time.Time) predicate.Account {
...
@@ -155,6 +155,16 @@ func OverloadUntil(v time.Time) predicate.Account {
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldOverloadUntil
,
v
))
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldOverloadUntil
,
v
))
}
}
// TempUnschedulableUntil applies equality check predicate on the "temp_unschedulable_until" field. It's identical to TempUnschedulableUntilEQ.
func
TempUnschedulableUntil
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableReason applies equality check predicate on the "temp_unschedulable_reason" field. It's identical to TempUnschedulableReasonEQ.
func
TempUnschedulableReason
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldTempUnschedulableReason
,
v
))
}
// SessionWindowStart applies equality check predicate on the "session_window_start" field. It's identical to SessionWindowStartEQ.
// SessionWindowStart applies equality check predicate on the "session_window_start" field. It's identical to SessionWindowStartEQ.
func
SessionWindowStart
(
v
time
.
Time
)
predicate
.
Account
{
func
SessionWindowStart
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldSessionWindowStart
,
v
))
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldSessionWindowStart
,
v
))
...
@@ -1130,6 +1140,131 @@ func OverloadUntilNotNil() predicate.Account {
...
@@ -1130,6 +1140,131 @@ func OverloadUntilNotNil() predicate.Account {
return
predicate
.
Account
(
sql
.
FieldNotNull
(
FieldOverloadUntil
))
return
predicate
.
Account
(
sql
.
FieldNotNull
(
FieldOverloadUntil
))
}
}
// TempUnschedulableUntilEQ applies the EQ predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilEQ
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilNEQ applies the NEQ predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilNEQ
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNEQ
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilIn applies the In predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilIn
(
vs
...
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldIn
(
FieldTempUnschedulableUntil
,
vs
...
))
}
// TempUnschedulableUntilNotIn applies the NotIn predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilNotIn
(
vs
...
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNotIn
(
FieldTempUnschedulableUntil
,
vs
...
))
}
// TempUnschedulableUntilGT applies the GT predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilGT
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldGT
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilGTE applies the GTE predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilGTE
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldGTE
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilLT applies the LT predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilLT
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldLT
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilLTE applies the LTE predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilLTE
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldLTE
(
FieldTempUnschedulableUntil
,
v
))
}
// TempUnschedulableUntilIsNil applies the IsNil predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilIsNil
()
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldIsNull
(
FieldTempUnschedulableUntil
))
}
// TempUnschedulableUntilNotNil applies the NotNil predicate on the "temp_unschedulable_until" field.
func
TempUnschedulableUntilNotNil
()
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNotNull
(
FieldTempUnschedulableUntil
))
}
// TempUnschedulableReasonEQ applies the EQ predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonEQ
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonNEQ applies the NEQ predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonNEQ
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNEQ
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonIn applies the In predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonIn
(
vs
...
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldIn
(
FieldTempUnschedulableReason
,
vs
...
))
}
// TempUnschedulableReasonNotIn applies the NotIn predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonNotIn
(
vs
...
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNotIn
(
FieldTempUnschedulableReason
,
vs
...
))
}
// TempUnschedulableReasonGT applies the GT predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonGT
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldGT
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonGTE applies the GTE predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonGTE
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldGTE
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonLT applies the LT predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonLT
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldLT
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonLTE applies the LTE predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonLTE
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldLTE
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonContains applies the Contains predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonContains
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldContains
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonHasPrefix applies the HasPrefix predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonHasPrefix
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldHasPrefix
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonHasSuffix applies the HasSuffix predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonHasSuffix
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldHasSuffix
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonIsNil applies the IsNil predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonIsNil
()
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldIsNull
(
FieldTempUnschedulableReason
))
}
// TempUnschedulableReasonNotNil applies the NotNil predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonNotNil
()
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldNotNull
(
FieldTempUnschedulableReason
))
}
// TempUnschedulableReasonEqualFold applies the EqualFold predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonEqualFold
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEqualFold
(
FieldTempUnschedulableReason
,
v
))
}
// TempUnschedulableReasonContainsFold applies the ContainsFold predicate on the "temp_unschedulable_reason" field.
func
TempUnschedulableReasonContainsFold
(
v
string
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldContainsFold
(
FieldTempUnschedulableReason
,
v
))
}
// SessionWindowStartEQ applies the EQ predicate on the "session_window_start" field.
// SessionWindowStartEQ applies the EQ predicate on the "session_window_start" field.
func
SessionWindowStartEQ
(
v
time
.
Time
)
predicate
.
Account
{
func
SessionWindowStartEQ
(
v
time
.
Time
)
predicate
.
Account
{
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldSessionWindowStart
,
v
))
return
predicate
.
Account
(
sql
.
FieldEQ
(
FieldSessionWindowStart
,
v
))
...
...
Prev
1
2
3
4
5
…
13
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