mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-16 23:53:33 +08:00
Merge pull request #7475 from Pluviobyte/codex/fix-proxy-restore-probe
fix(proxies): invalidate billing probe on fallback restore
This commit is contained in:
@@ -3887,8 +3887,12 @@ func (r *accountRepository) ResetQuotaUsedAndClearRateLimitCooldown(ctx context.
|
||||
// 仅当 proxy_fallback_origin_id IS NOT NULL 时执行更新;
|
||||
// 若影响行数为 0,则返回 ErrAccountNotInFallback(账号存在但不在 fallback 状态)。
|
||||
func (r *accountRepository) RevertProxyFallback(ctx context.Context, accountID int64) error {
|
||||
// Probe snapshots belong to the network identity; invalidate only on a real proxy change.
|
||||
res, err := r.sql.ExecContext(ctx, `
|
||||
UPDATE accounts SET proxy_id=proxy_fallback_origin_id, proxy_fallback_origin_id=NULL, updated_at=NOW()
|
||||
UPDATE accounts SET
|
||||
extra=CASE WHEN type='apikey' AND proxy_id IS DISTINCT FROM proxy_fallback_origin_id
|
||||
THEN extra - 'upstream_billing_probe' ELSE extra END,
|
||||
proxy_id=proxy_fallback_origin_id, proxy_fallback_origin_id=NULL, updated_at=NOW()
|
||||
WHERE id=$1 AND proxy_fallback_origin_id IS NOT NULL AND deleted_at IS NULL`, accountID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//go:build integration
|
||||
|
||||
package repository
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
)
|
||||
|
||||
func (s *ProxyExpirySuite) TestRevertClearsBillingProbe() {
|
||||
original := s.mkProxy("original", service.FallbackModeDirect, nil, nil)
|
||||
backup := s.mkProxy("backup", service.FallbackModeNone, nil, nil)
|
||||
account := s.mkAccountWithProxy(backup)
|
||||
_, err := s.tx.ExecContext(s.ctx, `UPDATE accounts SET type='apikey',proxy_fallback_origin_id=$1,extra='{"upstream_billing_probe_enabled":true,"upstream_billing_probe":{"status":"ok","data":{"balance":123}},"keep_me":true}'::jsonb WHERE id=$2`, original, account)
|
||||
s.Require().NoError(err)
|
||||
repo := newAccountRepositoryWithSQL(s.tx.Client(), s.tx, nil)
|
||||
s.Require().NoError(repo.RevertProxyFallback(s.ctx, account))
|
||||
s.Require().Equal(&original, s.accountProxyID(account))
|
||||
var raw []byte
|
||||
s.Require().NoError(scanSingleRow(s.ctx, s.tx, `SELECT extra FROM accounts WHERE id=$1`, []any{account}, &raw))
|
||||
var extra map[string]any
|
||||
s.Require().NoError(json.Unmarshal(raw, &extra))
|
||||
s.NotContains(extra, "upstream_billing_probe", "probe from previous network identity must be invalidated")
|
||||
s.Equal(true, extra["keep_me"])
|
||||
}
|
||||
|
||||
func (s *ProxyExpirySuite) TestRevertProbeInvalidationScope() {
|
||||
for _, tc := range []struct {
|
||||
name, kind string
|
||||
same, direct, clear bool
|
||||
}{
|
||||
{"changed API key", "apikey", false, false, true},
|
||||
{"direct API key", "apikey", false, true, true},
|
||||
{"same proxy", "apikey", true, false, false},
|
||||
{"oauth metadata", "oauth", false, false, false},
|
||||
} {
|
||||
s.Run(tc.name, func() {
|
||||
original := s.mkProxy("origin", service.FallbackModeNone, nil, nil)
|
||||
current := s.mkProxy("current", service.FallbackModeNone, nil, nil)
|
||||
if tc.same {
|
||||
current = original
|
||||
}
|
||||
account := s.mkAccountWithProxy(current)
|
||||
_, err := s.tx.ExecContext(s.ctx, `UPDATE accounts SET type=$1,proxy_fallback_origin_id=$2,extra='{"upstream_billing_probe_enabled":true,"upstream_billing_probe":{"status":"ok"},"keep_me":true}'::jsonb WHERE id=$3`, tc.kind, original, account)
|
||||
s.Require().NoError(err)
|
||||
if tc.direct {
|
||||
_, err = s.tx.ExecContext(s.ctx, `UPDATE accounts SET proxy_id=NULL WHERE id=$1`, account)
|
||||
s.Require().NoError(err)
|
||||
}
|
||||
repo := newAccountRepositoryWithSQL(s.tx.Client(), s.tx, nil)
|
||||
s.Require().NoError(repo.RevertProxyFallback(s.ctx, account))
|
||||
var raw []byte
|
||||
s.Require().NoError(scanSingleRow(s.ctx, s.tx, `SELECT extra FROM accounts WHERE id=$1`, []any{account}, &raw))
|
||||
var extra map[string]any
|
||||
s.Require().NoError(json.Unmarshal(raw, &extra))
|
||||
if tc.clear {
|
||||
s.NotContains(extra, "upstream_billing_probe")
|
||||
} else {
|
||||
s.Contains(extra, "upstream_billing_probe")
|
||||
}
|
||||
s.Equal(true, extra["upstream_billing_probe_enabled"])
|
||||
s.Equal(true, extra["keep_me"])
|
||||
s.Equal(&original, s.accountProxyID(account))
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user