feat: add Pi provider managed resources
This commit is contained in:
44
electron/coding-runtime/pi/provider-refresh.ts
Normal file
44
electron/coding-runtime/pi/provider-refresh.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export interface PiProviderAuthRecoveryOptions<T> {
|
||||
accountId: string;
|
||||
operation: (attempt: 0 | 1) => Promise<T>;
|
||||
isAuthenticationError: (error: unknown) => boolean;
|
||||
refreshCredential: () => Promise<void>;
|
||||
reopenWorker: () => Promise<void>;
|
||||
}
|
||||
|
||||
export class PiProviderRefreshCoordinator {
|
||||
private readonly refreshes = new Map<string, Promise<void>>();
|
||||
|
||||
get pendingAccountCount(): number {
|
||||
return this.refreshes.size;
|
||||
}
|
||||
|
||||
async refreshAccount(accountId: string, refresh: () => Promise<void>): Promise<void> {
|
||||
const normalizedAccountId = accountId.trim();
|
||||
if (!normalizedAccountId) throw new Error('Provider account id is required');
|
||||
let pending = this.refreshes.get(normalizedAccountId);
|
||||
if (!pending) {
|
||||
pending = Promise.resolve()
|
||||
.then(refresh)
|
||||
.finally(() => {
|
||||
if (this.refreshes.get(normalizedAccountId) === pending) {
|
||||
this.refreshes.delete(normalizedAccountId);
|
||||
}
|
||||
});
|
||||
this.refreshes.set(normalizedAccountId, pending);
|
||||
}
|
||||
await pending;
|
||||
}
|
||||
|
||||
async withSingleAuthRecovery<T>(options: PiProviderAuthRecoveryOptions<T>): Promise<T> {
|
||||
try {
|
||||
return await options.operation(0);
|
||||
} catch (error) {
|
||||
if (!options.isAuthenticationError(error)) throw error;
|
||||
}
|
||||
|
||||
await this.refreshAccount(options.accountId, options.refreshCredential);
|
||||
await options.reopenWorker();
|
||||
return await options.operation(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user