统一 AGC 平台会话转移状态
让登录、refresh 和退出共享 auth-transition operation 投影 保留 generation、Runner phase、成功、失败和不确定状态
This commit is contained in:
@@ -6,6 +6,11 @@ import {
|
||||
refreshClientAuthAccessToken,
|
||||
} from './clientAuth';
|
||||
import { getClientServerBaseUrl } from './clientHttp';
|
||||
import {
|
||||
type ClientOperation,
|
||||
createClientOperation,
|
||||
transitionClientOperation,
|
||||
} from './clientOperation';
|
||||
|
||||
const ACCESS_TOKEN_STORAGE_KEY = 'genarrative.auth.access-token.v1';
|
||||
|
||||
@@ -34,12 +39,20 @@ let committedPlatformSession: CommittedPlatformSession | null = null;
|
||||
let desiredPlatformSession: CommittedPlatformSession | null = null;
|
||||
let platformSessionRefreshPromise: Promise<PlatformSessionRefreshResult> | null =
|
||||
null;
|
||||
let platformSessionOperation: ClientOperation<
|
||||
'auth-transition',
|
||||
{ userId: string | null }
|
||||
> | null = null;
|
||||
let platformSessionNativeMutationTail: Promise<void> = Promise.resolve();
|
||||
const platformSessionRefreshListeners =
|
||||
new Set<PlatformSessionRefreshListener>();
|
||||
const platformSessionGenerationListeners =
|
||||
new Set<PlatformSessionGenerationListener>();
|
||||
|
||||
export function getPlatformSessionOperation() {
|
||||
return platformSessionOperation;
|
||||
}
|
||||
|
||||
function restoreCommittedAccessToken() {
|
||||
if (committedPlatformSession?.accessToken) {
|
||||
window.localStorage.setItem(
|
||||
@@ -259,15 +272,44 @@ export async function commitAuthenticatedPlatformSession(
|
||||
if (!accessToken) {
|
||||
throw new Error('陶泥儿登录凭据缺失,请重新登录');
|
||||
}
|
||||
const operation = createClientOperation(
|
||||
'auth-transition',
|
||||
{ userId: user.id },
|
||||
{
|
||||
scope: { apiBaseUrl, sessionGeneration: expectedGeneration },
|
||||
deadlineMs: 45_000,
|
||||
cancellable: false,
|
||||
},
|
||||
);
|
||||
platformSessionOperation = transitionClientOperation(operation, 'runner');
|
||||
return enqueuePlatformSessionNativeMutation(async () => {
|
||||
const session = await commitPlatformSession(
|
||||
user,
|
||||
accessToken,
|
||||
apiBaseUrl,
|
||||
expectedGeneration,
|
||||
);
|
||||
if (!session) return null;
|
||||
return session.generation;
|
||||
try {
|
||||
const session = await commitPlatformSession(
|
||||
user,
|
||||
accessToken,
|
||||
apiBaseUrl,
|
||||
expectedGeneration,
|
||||
);
|
||||
if (!session) {
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'unknown',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'success',
|
||||
{ scope: { sessionGeneration: session.generation } },
|
||||
);
|
||||
return session.generation;
|
||||
} catch (error) {
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'retryable-failure',
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -375,30 +417,64 @@ export function subscribePlatformSessionGeneration(
|
||||
}
|
||||
|
||||
export async function clearCommittedPlatformSession(generation: number) {
|
||||
const operation = createClientOperation(
|
||||
'auth-transition',
|
||||
{ userId: null },
|
||||
{
|
||||
scope: { sessionGeneration: generation },
|
||||
deadlineMs: 45_000,
|
||||
cancellable: false,
|
||||
},
|
||||
);
|
||||
platformSessionOperation = transitionClientOperation(operation, 'runner');
|
||||
return enqueuePlatformSessionNativeMutation(async () => {
|
||||
if (platformAuthGeneration !== generation) {
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
return;
|
||||
}
|
||||
desiredPlatformSession = null;
|
||||
const nativeGeneration = await reserveNativePlatformSessionGeneration();
|
||||
try {
|
||||
await clearNativePlatformSession(nativeGeneration);
|
||||
} catch {
|
||||
if (platformAuthGeneration === generation) {
|
||||
desiredPlatformSession = null;
|
||||
if (platformAuthGeneration !== generation) {
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'unknown',
|
||||
);
|
||||
return;
|
||||
}
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
return;
|
||||
desiredPlatformSession = null;
|
||||
const nativeGeneration = await reserveNativePlatformSessionGeneration();
|
||||
try {
|
||||
await clearNativePlatformSession(nativeGeneration);
|
||||
} catch {
|
||||
if (platformAuthGeneration === generation) {
|
||||
desiredPlatformSession = null;
|
||||
}
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'retryable-failure',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (platformAuthGeneration !== generation) {
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'unknown',
|
||||
);
|
||||
return;
|
||||
}
|
||||
committedPlatformSession = null;
|
||||
desiredPlatformSession = null;
|
||||
restoreCommittedAccessToken();
|
||||
notifyPlatformSessionGeneration();
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'success',
|
||||
);
|
||||
} catch (error) {
|
||||
platformSessionOperation = transitionClientOperation(
|
||||
operation,
|
||||
'retryable-failure',
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
if (platformAuthGeneration !== generation) {
|
||||
await reconcileNativePlatformSessionToCurrentAuthority();
|
||||
return;
|
||||
}
|
||||
committedPlatformSession = null;
|
||||
desiredPlatformSession = null;
|
||||
restoreCommittedAccessToken();
|
||||
notifyPlatformSessionGeneration();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -409,6 +485,7 @@ export function resetPlatformSessionStateForTests() {
|
||||
committedPlatformSession = null;
|
||||
desiredPlatformSession = null;
|
||||
platformSessionRefreshPromise = null;
|
||||
platformSessionOperation = null;
|
||||
platformSessionNativeMutationTail = Promise.resolve();
|
||||
platformSessionRefreshListeners.clear();
|
||||
platformSessionGenerationListeners.clear();
|
||||
|
||||
Reference in New Issue
Block a user