mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 10:15:40 +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:
1 parent
01fe780514
commit
9d2442f9fa
1 file changed
+62
-4
@@ -135,6 +135,14 @@ export function getAccountsRegistryPath(): string {
|
|||||||
return path.join(getCliproxyDir(), 'accounts.json');
|
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
|
* Load accounts registry
|
||||||
*/
|
*/
|
||||||
@@ -176,10 +184,12 @@ export function saveAccountsRegistry(registry: AccountsRegistry): void {
|
|||||||
/**
|
/**
|
||||||
* Sync registry with actual token files
|
* Sync registry with actual token files
|
||||||
* Removes stale entries where token file no longer exists
|
* Removes stale entries where token file no longer exists
|
||||||
|
* For paused accounts, checks both auth/ and paused/ directories
|
||||||
* Called automatically when loading accounts
|
* Called automatically when loading accounts
|
||||||
*/
|
*/
|
||||||
function syncRegistryWithTokenFiles(registry: AccountsRegistry): boolean {
|
function syncRegistryWithTokenFiles(registry: AccountsRegistry): boolean {
|
||||||
const authDir = getAuthDir();
|
const authDir = getAuthDir();
|
||||||
|
const pausedDir = getPausedDir();
|
||||||
let modified = false;
|
let modified = false;
|
||||||
|
|
||||||
for (const [_providerName, providerAccounts] of Object.entries(registry.providers)) {
|
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)) {
|
for (const [accountId, meta] of Object.entries(providerAccounts.accounts)) {
|
||||||
const tokenPath = path.join(authDir, meta.tokenFile);
|
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);
|
staleIds.push(accountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,6 +412,7 @@ export function setDefaultAccount(provider: CLIProxyProvider, accountId: string)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause an account (skip in quota rotation)
|
* 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 {
|
export function pauseAccount(provider: CLIProxyProvider, accountId: string): boolean {
|
||||||
const registry = loadAccountsRegistry();
|
const registry = loadAccountsRegistry();
|
||||||
@@ -404,6 +422,21 @@ export function pauseAccount(provider: CLIProxyProvider, accountId: string): boo
|
|||||||
return false;
|
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].paused = true;
|
||||||
providerAccounts.accounts[accountId].pausedAt = new Date().toISOString();
|
providerAccounts.accounts[accountId].pausedAt = new Date().toISOString();
|
||||||
saveAccountsRegistry(registry);
|
saveAccountsRegistry(registry);
|
||||||
@@ -412,6 +445,7 @@ export function pauseAccount(provider: CLIProxyProvider, accountId: string): boo
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume a paused account
|
* 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 {
|
export function resumeAccount(provider: CLIProxyProvider, accountId: string): boolean {
|
||||||
const registry = loadAccountsRegistry();
|
const registry = loadAccountsRegistry();
|
||||||
@@ -421,6 +455,17 @@ export function resumeAccount(provider: CLIProxyProvider, accountId: string): bo
|
|||||||
return false;
|
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].paused = false;
|
||||||
providerAccounts.accounts[accountId].pausedAt = undefined;
|
providerAccounts.accounts[accountId].pausedAt = undefined;
|
||||||
saveAccountsRegistry(registry);
|
saveAccountsRegistry(registry);
|
||||||
@@ -474,11 +519,12 @@ export function removeAccount(provider: CLIProxyProvider, accountId: string): bo
|
|||||||
return false;
|
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 tokenFile = providerAccounts.accounts[accountId].tokenFile;
|
||||||
const tokenPath = path.join(getAuthDir(), 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)) {
|
if (fs.existsSync(tokenPath)) {
|
||||||
try {
|
try {
|
||||||
fs.unlinkSync(tokenPath);
|
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
|
// Remove from registry
|
||||||
delete providerAccounts.accounts[accountId];
|
delete providerAccounts.accounts[accountId];
|
||||||
|
|
||||||
@@ -547,6 +602,7 @@ export function touchAccount(provider: CLIProxyProvider, accountId: string): voi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get token file path for an account
|
* 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 {
|
export function getAccountTokenPath(provider: CLIProxyProvider, accountId?: string): string | null {
|
||||||
const account = accountId ? getAccount(provider, accountId) : getDefaultAccount(provider);
|
const account = accountId ? getAccount(provider, accountId) : getDefaultAccount(provider);
|
||||||
@@ -555,7 +611,9 @@ export function getAccountTokenPath(provider: CLIProxyProvider, accountId?: stri
|
|||||||
return null;
|
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