mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 06:16:37 +00:00
fix(cliproxy): move token files when pausing/resuming accounts
Pausing an account now physically moves the token file to auth/paused/ subdirectory, preventing CLIProxyAPI from discovering and using it. Resume moves the file back to auth/ directory. Changes: - Add getPausedDir() helper for paused tokens location - Update pauseAccount() to move token to paused/ subdir - Update resumeAccount() to move token back to auth/ - Update syncRegistryWithTokenFiles() to check both directories - Update removeAccount() to clean up from both directories - Update getAccountTokenPath() to return correct path based on state Fixes #337
This commit is contained in:
@@ -135,6 +135,14 @@ export function getAccountsRegistryPath(): string {
|
||||
return path.join(getCliproxyDir(), 'accounts.json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to paused tokens directory
|
||||
* Paused tokens are moved here so CLIProxyAPI won't discover them
|
||||
*/
|
||||
export function getPausedDir(): string {
|
||||
return path.join(getAuthDir(), 'paused');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load accounts registry
|
||||
*/
|
||||
@@ -176,10 +184,12 @@ export function saveAccountsRegistry(registry: AccountsRegistry): void {
|
||||
/**
|
||||
* Sync registry with actual token files
|
||||
* Removes stale entries where token file no longer exists
|
||||
* For paused accounts, checks both auth/ and paused/ directories
|
||||
* Called automatically when loading accounts
|
||||
*/
|
||||
function syncRegistryWithTokenFiles(registry: AccountsRegistry): boolean {
|
||||
const authDir = getAuthDir();
|
||||
const pausedDir = getPausedDir();
|
||||
let modified = false;
|
||||
|
||||
for (const [_providerName, providerAccounts] of Object.entries(registry.providers)) {
|
||||
@@ -189,7 +199,14 @@ function syncRegistryWithTokenFiles(registry: AccountsRegistry): boolean {
|
||||
|
||||
for (const [accountId, meta] of Object.entries(providerAccounts.accounts)) {
|
||||
const tokenPath = path.join(authDir, meta.tokenFile);
|
||||
if (!fs.existsSync(tokenPath)) {
|
||||
const pausedPath = path.join(pausedDir, meta.tokenFile);
|
||||
|
||||
// For paused accounts, check paused dir; for active accounts, check auth dir
|
||||
const expectedPath = meta.paused ? pausedPath : tokenPath;
|
||||
// Also accept if file exists in either location (handles edge cases)
|
||||
const existsAnywhere = fs.existsSync(tokenPath) || fs.existsSync(pausedPath);
|
||||
|
||||
if (!fs.existsSync(expectedPath) && !existsAnywhere) {
|
||||
staleIds.push(accountId);
|
||||
}
|
||||
}
|
||||
@@ -395,6 +412,7 @@ export function setDefaultAccount(provider: CLIProxyProvider, accountId: string)
|
||||
|
||||
/**
|
||||
* Pause an account (skip in quota rotation)
|
||||
* Moves token file to paused/ subdir so CLIProxyAPI won't discover it
|
||||
*/
|
||||
export function pauseAccount(provider: CLIProxyProvider, accountId: string): boolean {
|
||||
const registry = loadAccountsRegistry();
|
||||
@@ -404,6 +422,21 @@ export function pauseAccount(provider: CLIProxyProvider, accountId: string): boo
|
||||
return false;
|
||||
}
|
||||
|
||||
const accountMeta = providerAccounts.accounts[accountId];
|
||||
const authDir = getAuthDir();
|
||||
const pausedDir = getPausedDir();
|
||||
const tokenPath = path.join(authDir, accountMeta.tokenFile);
|
||||
const pausedPath = path.join(pausedDir, accountMeta.tokenFile);
|
||||
|
||||
// Move token file to paused directory (if it exists in auth dir)
|
||||
if (fs.existsSync(tokenPath)) {
|
||||
// Create paused directory if it doesn't exist
|
||||
if (!fs.existsSync(pausedDir)) {
|
||||
fs.mkdirSync(pausedDir, { recursive: true, mode: 0o700 });
|
||||
}
|
||||
fs.renameSync(tokenPath, pausedPath);
|
||||
}
|
||||
|
||||
providerAccounts.accounts[accountId].paused = true;
|
||||
providerAccounts.accounts[accountId].pausedAt = new Date().toISOString();
|
||||
saveAccountsRegistry(registry);
|
||||
@@ -412,6 +445,7 @@ export function pauseAccount(provider: CLIProxyProvider, accountId: string): boo
|
||||
|
||||
/**
|
||||
* Resume a paused account
|
||||
* Moves token file back from paused/ to auth/ so CLIProxyAPI can discover it
|
||||
*/
|
||||
export function resumeAccount(provider: CLIProxyProvider, accountId: string): boolean {
|
||||
const registry = loadAccountsRegistry();
|
||||
@@ -421,6 +455,17 @@ export function resumeAccount(provider: CLIProxyProvider, accountId: string): bo
|
||||
return false;
|
||||
}
|
||||
|
||||
const accountMeta = providerAccounts.accounts[accountId];
|
||||
const authDir = getAuthDir();
|
||||
const pausedDir = getPausedDir();
|
||||
const tokenPath = path.join(authDir, accountMeta.tokenFile);
|
||||
const pausedPath = path.join(pausedDir, accountMeta.tokenFile);
|
||||
|
||||
// Move token file back from paused directory (if it exists in paused dir)
|
||||
if (fs.existsSync(pausedPath)) {
|
||||
fs.renameSync(pausedPath, tokenPath);
|
||||
}
|
||||
|
||||
providerAccounts.accounts[accountId].paused = false;
|
||||
providerAccounts.accounts[accountId].pausedAt = undefined;
|
||||
saveAccountsRegistry(registry);
|
||||
@@ -474,11 +519,12 @@ export function removeAccount(provider: CLIProxyProvider, accountId: string): bo
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get token file to delete
|
||||
// Get token file to delete (check both auth and paused directories)
|
||||
const tokenFile = providerAccounts.accounts[accountId].tokenFile;
|
||||
const tokenPath = path.join(getAuthDir(), tokenFile);
|
||||
const pausedPath = path.join(getPausedDir(), tokenFile);
|
||||
|
||||
// Delete token file
|
||||
// Delete token file from auth directory
|
||||
if (fs.existsSync(tokenPath)) {
|
||||
try {
|
||||
fs.unlinkSync(tokenPath);
|
||||
@@ -487,6 +533,15 @@ export function removeAccount(provider: CLIProxyProvider, accountId: string): bo
|
||||
}
|
||||
}
|
||||
|
||||
// Also delete from paused directory if it exists there
|
||||
if (fs.existsSync(pausedPath)) {
|
||||
try {
|
||||
fs.unlinkSync(pausedPath);
|
||||
} catch {
|
||||
// Ignore deletion errors
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from registry
|
||||
delete providerAccounts.accounts[accountId];
|
||||
|
||||
@@ -547,6 +602,7 @@ export function touchAccount(provider: CLIProxyProvider, accountId: string): voi
|
||||
|
||||
/**
|
||||
* Get token file path for an account
|
||||
* Returns path in paused/ dir if account is paused, otherwise auth/
|
||||
*/
|
||||
export function getAccountTokenPath(provider: CLIProxyProvider, accountId?: string): string | null {
|
||||
const account = accountId ? getAccount(provider, accountId) : getDefaultAccount(provider);
|
||||
@@ -555,7 +611,9 @@ export function getAccountTokenPath(provider: CLIProxyProvider, accountId?: stri
|
||||
return null;
|
||||
}
|
||||
|
||||
return path.join(getAuthDir(), account.tokenFile);
|
||||
// Return path from paused directory if account is paused
|
||||
const baseDir = account.paused ? getPausedDir() : getAuthDir();
|
||||
return path.join(baseDir, account.tokenFile);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user