mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-25 08:02:04 +00:00
refactor(auth): unify external CLI credential sync
This commit is contained in:
@@ -21,7 +21,7 @@ type CachedValue<T> = {
|
||||
value: T | null;
|
||||
readAt: number;
|
||||
cacheKey: string;
|
||||
sourceMtimeMs?: number | null;
|
||||
sourceFingerprint?: number | string | null;
|
||||
};
|
||||
|
||||
let claudeCliCache: CachedValue<ClaudeCliCredential> | null = null;
|
||||
@@ -157,6 +157,45 @@ function readFileMtimeMs(filePath: string): number | null {
|
||||
}
|
||||
}
|
||||
|
||||
function readCachedCliCredential<T>(options: {
|
||||
ttlMs: number;
|
||||
cache: CachedValue<T> | null;
|
||||
cacheKey: string;
|
||||
read: () => T | null;
|
||||
setCache: (next: CachedValue<T> | null) => void;
|
||||
readSourceFingerprint?: () => number | string | null;
|
||||
}): T | null {
|
||||
const { ttlMs, cache, cacheKey, read, setCache, readSourceFingerprint } = options;
|
||||
if (ttlMs <= 0) {
|
||||
return read();
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const sourceFingerprint = readSourceFingerprint?.();
|
||||
if (
|
||||
cache &&
|
||||
cache.cacheKey === cacheKey &&
|
||||
cache.sourceFingerprint === sourceFingerprint &&
|
||||
now - cache.readAt < ttlMs
|
||||
) {
|
||||
return cache.value;
|
||||
}
|
||||
|
||||
const value = read();
|
||||
const cachedSourceFingerprint = readSourceFingerprint?.();
|
||||
if (!readSourceFingerprint || cachedSourceFingerprint === sourceFingerprint) {
|
||||
setCache({
|
||||
value,
|
||||
readAt: now,
|
||||
cacheKey,
|
||||
sourceFingerprint: cachedSourceFingerprint,
|
||||
});
|
||||
} else {
|
||||
setCache(null);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function computeCodexKeychainAccount(codexHome: string) {
|
||||
const hash = createHash("sha256").update(codexHome).digest("hex");
|
||||
return `cli|${hash.slice(0, 16)}`;
|
||||
@@ -334,27 +373,21 @@ export function readClaudeCliCredentialsCached(options?: {
|
||||
homeDir?: string;
|
||||
execSync?: ExecSyncFn;
|
||||
}): ClaudeCliCredential | null {
|
||||
const ttlMs = options?.ttlMs ?? 0;
|
||||
const now = Date.now();
|
||||
const cacheKey = resolveClaudeCliCredentialsPath(options?.homeDir);
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
claudeCliCache &&
|
||||
claudeCliCache.cacheKey === cacheKey &&
|
||||
now - claudeCliCache.readAt < ttlMs
|
||||
) {
|
||||
return claudeCliCache.value;
|
||||
}
|
||||
const value = readClaudeCliCredentials({
|
||||
allowKeychainPrompt: options?.allowKeychainPrompt,
|
||||
platform: options?.platform,
|
||||
homeDir: options?.homeDir,
|
||||
execSync: options?.execSync,
|
||||
return readCachedCliCredential({
|
||||
ttlMs: options?.ttlMs ?? 0,
|
||||
cache: claudeCliCache,
|
||||
cacheKey: resolveClaudeCliCredentialsPath(options?.homeDir),
|
||||
read: () =>
|
||||
readClaudeCliCredentials({
|
||||
allowKeychainPrompt: options?.allowKeychainPrompt,
|
||||
platform: options?.platform,
|
||||
homeDir: options?.homeDir,
|
||||
execSync: options?.execSync,
|
||||
}),
|
||||
setCache: (next) => {
|
||||
claudeCliCache = next;
|
||||
},
|
||||
});
|
||||
if (ttlMs > 0) {
|
||||
claudeCliCache = { value, readAt: now, cacheKey };
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function writeClaudeCliKeychainCredentials(
|
||||
@@ -533,78 +566,53 @@ export function readCodexCliCredentialsCached(options?: {
|
||||
platform?: NodeJS.Platform;
|
||||
execSync?: ExecSyncFn;
|
||||
}): CodexCliCredential | null {
|
||||
const ttlMs = options?.ttlMs ?? 0;
|
||||
const now = Date.now();
|
||||
const authPath = resolveCodexCliAuthPath();
|
||||
const cacheKey = `${options?.platform ?? process.platform}|${authPath}`;
|
||||
const sourceMtimeMs = readFileMtimeMs(authPath);
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
codexCliCache &&
|
||||
codexCliCache.cacheKey === cacheKey &&
|
||||
codexCliCache.sourceMtimeMs === sourceMtimeMs &&
|
||||
now - codexCliCache.readAt < ttlMs
|
||||
) {
|
||||
return codexCliCache.value;
|
||||
}
|
||||
const value = readCodexCliCredentials({
|
||||
platform: options?.platform,
|
||||
execSync: options?.execSync,
|
||||
return readCachedCliCredential({
|
||||
ttlMs: options?.ttlMs ?? 0,
|
||||
cache: codexCliCache,
|
||||
cacheKey: `${options?.platform ?? process.platform}|${authPath}`,
|
||||
read: () =>
|
||||
readCodexCliCredentials({
|
||||
platform: options?.platform,
|
||||
execSync: options?.execSync,
|
||||
}),
|
||||
setCache: (next) => {
|
||||
codexCliCache = next;
|
||||
},
|
||||
readSourceFingerprint: () => readFileMtimeMs(authPath),
|
||||
});
|
||||
const cachedSourceMtimeMs = readFileMtimeMs(authPath);
|
||||
if (ttlMs > 0 && cachedSourceMtimeMs === sourceMtimeMs) {
|
||||
codexCliCache = {
|
||||
value,
|
||||
readAt: now,
|
||||
cacheKey,
|
||||
sourceMtimeMs: cachedSourceMtimeMs,
|
||||
};
|
||||
} else if (ttlMs > 0) {
|
||||
codexCliCache = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function readQwenCliCredentialsCached(options?: {
|
||||
ttlMs?: number;
|
||||
homeDir?: string;
|
||||
}): QwenCliCredential | null {
|
||||
const ttlMs = options?.ttlMs ?? 0;
|
||||
const now = Date.now();
|
||||
const cacheKey = resolveQwenCliCredentialsPath(options?.homeDir);
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
qwenCliCache &&
|
||||
qwenCliCache.cacheKey === cacheKey &&
|
||||
now - qwenCliCache.readAt < ttlMs
|
||||
) {
|
||||
return qwenCliCache.value;
|
||||
}
|
||||
const value = readQwenCliCredentials({ homeDir: options?.homeDir });
|
||||
if (ttlMs > 0) {
|
||||
qwenCliCache = { value, readAt: now, cacheKey };
|
||||
}
|
||||
return value;
|
||||
const credPath = resolveQwenCliCredentialsPath(options?.homeDir);
|
||||
return readCachedCliCredential({
|
||||
ttlMs: options?.ttlMs ?? 0,
|
||||
cache: qwenCliCache,
|
||||
cacheKey: credPath,
|
||||
read: () => readQwenCliCredentials({ homeDir: options?.homeDir }),
|
||||
setCache: (next) => {
|
||||
qwenCliCache = next;
|
||||
},
|
||||
readSourceFingerprint: () => readFileMtimeMs(credPath),
|
||||
});
|
||||
}
|
||||
|
||||
export function readMiniMaxCliCredentialsCached(options?: {
|
||||
ttlMs?: number;
|
||||
homeDir?: string;
|
||||
}): MiniMaxCliCredential | null {
|
||||
const ttlMs = options?.ttlMs ?? 0;
|
||||
const now = Date.now();
|
||||
const cacheKey = resolveMiniMaxCliCredentialsPath(options?.homeDir);
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
minimaxCliCache &&
|
||||
minimaxCliCache.cacheKey === cacheKey &&
|
||||
now - minimaxCliCache.readAt < ttlMs
|
||||
) {
|
||||
return minimaxCliCache.value;
|
||||
}
|
||||
const value = readMiniMaxCliCredentials({ homeDir: options?.homeDir });
|
||||
if (ttlMs > 0) {
|
||||
minimaxCliCache = { value, readAt: now, cacheKey };
|
||||
}
|
||||
return value;
|
||||
const credPath = resolveMiniMaxCliCredentialsPath(options?.homeDir);
|
||||
return readCachedCliCredential({
|
||||
ttlMs: options?.ttlMs ?? 0,
|
||||
cache: minimaxCliCache,
|
||||
cacheKey: credPath,
|
||||
read: () => readMiniMaxCliCredentials({ homeDir: options?.homeDir }),
|
||||
setCache: (next) => {
|
||||
minimaxCliCache = next;
|
||||
},
|
||||
readSourceFingerprint: () => readFileMtimeMs(credPath),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user