更新导入设计
This commit is contained in:
@@ -862,26 +862,12 @@ func (s *TokenService) ImportGrokToken(ctx context.Context, ssoToken, tokenID st
|
|||||||
return nil, errors.New("not a grok sso token")
|
return nil, errors.New("not a grok sso token")
|
||||||
}
|
}
|
||||||
sid := grok.SessionIDFromToken(ssoToken)
|
sid := grok.SessionIDFromToken(ssoToken)
|
||||||
// Resolve the real account email up front (GET /api/auth/session) for dedup +
|
// Fully async, no dedup: every import mints a fresh row (a passed-in tokenID is
|
||||||
// display — the sso session_id rotates per login, so email is the stable id.
|
// an explicit edit → update). We do NOT look up an existing account by
|
||||||
email := ""
|
// email/session_id, and we leave account_email empty — email, quota and
|
||||||
if s.grok != nil {
|
// recovery time are all filled off-thread by checkPendingGrok, which also
|
||||||
s.applyProxy(ctx)
|
// disables the account if the sso session is dead.
|
||||||
// Best-effort email resolution. A dead/blocked probe must NOT block import:
|
if strings.TrimSpace(tokenID) == "" {
|
||||||
// land the account and let the async checkPendingGrok disable it if the
|
|
||||||
// session is truly dead. Empty email just falls back to the session id.
|
|
||||||
if e, _, ferr := s.grok.FetchSession(ctx, ssoToken); ferr == nil {
|
|
||||||
email = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idKey := email
|
|
||||||
if idKey == "" {
|
|
||||||
idKey = sid
|
|
||||||
}
|
|
||||||
// Identity is (pool, email): reuse the row for this account, else mint.
|
|
||||||
if existing, _ := s.tokens.GetByPoolEmail(ctx, "grok", idKey); existing != nil {
|
|
||||||
tokenID = existing.ID
|
|
||||||
} else if idKey != "" || tokenID == "" {
|
|
||||||
tokenID = newTokenID("grok")
|
tokenID = newTokenID("grok")
|
||||||
}
|
}
|
||||||
meta := datatypes.JSONMap{"pending_check": true}
|
meta := datatypes.JSONMap{"pending_check": true}
|
||||||
@@ -900,11 +886,6 @@ func (s *TokenService) ImportGrokToken(ctx context.Context, ssoToken, tokenID st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idKey != "" {
|
|
||||||
if updated, uerr := s.tokens.Update(ctx, "grok", tokenID, map[string]any{"account_email": idKey}); uerr == nil {
|
|
||||||
item = updated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
go s.checkPendingGrok(tokenID, ssoToken)
|
go s.checkPendingGrok(tokenID, ssoToken)
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ async function doSmartImport() {
|
|||||||
const errs = []
|
const errs = []
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
const it = items[i]
|
const it = items[i]
|
||||||
setStatus(`正在导入 ${i + 1}/${items.length} (${it.type})…`)
|
|
||||||
try {
|
try {
|
||||||
const r = it.type === 'openai'
|
const r = it.type === 'openai'
|
||||||
? await api('/tokens/import-chatgpt-token', jsonBody('POST', { access_token: it.value }))
|
? await api('/tokens/import-chatgpt-token', jsonBody('POST', { access_token: it.value }))
|
||||||
@@ -77,9 +76,10 @@ async function doSmartImport() {
|
|||||||
// Quota isn't checked here — the server probes each token off-thread and the
|
// Quota isn't checked here — the server probes each token off-thread and the
|
||||||
// account list flips pending → active/dead on its own.
|
// account list flips pending → active/dead on its own.
|
||||||
if (fail === 0) {
|
if (fail === 0) {
|
||||||
setStatus(`✓ 导入 ${ok} 项 · 正在后台检测额度…`)
|
// Close immediately on success — the account lands in the table right away
|
||||||
|
// and the server backfills quota/email off-thread (pending → active/dead).
|
||||||
emit('imported')
|
emit('imported')
|
||||||
setTimeout(() => emit('close'), 1000)
|
emit('close')
|
||||||
} else {
|
} else {
|
||||||
setStatus(`成功 ${ok} · 失败 ${fail} · ${errs.slice(0, 3).join(' | ')}`, true)
|
setStatus(`成功 ${ok} · 失败 ${fail} · ${errs.slice(0, 3).join(' | ')}`, true)
|
||||||
emit('imported')
|
emit('imported')
|
||||||
|
|||||||
Reference in New Issue
Block a user