refactor(core): introduce EventBus and refactor store infrastructure
- Add EventBus for decoupled event-driven communication between services - Add EventSubscriber component for centralized event handling - Add requestDedupe utility for shared request deduplication - Refactor api/wsService to use eventBus instead of direct router navigation - Extract MessageMapper.toCachedMessages for consistent message mapping - Remove deprecated BaseManager and CacheBus classes - Improve @mention rendering with memberMap support in segment rendering - Update hooks to use useRef instead of useState for fetch tracking
This commit is contained in:
@@ -6,11 +6,10 @@
|
||||
*/
|
||||
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { CommonActions } from '@react-navigation/native';
|
||||
import Constants from 'expo-constants';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
import { hrefVerificationGuide } from '../navigation/hrefs';
|
||||
import { eventBus } from '@/core/events/EventBus';
|
||||
|
||||
// 生产地址 https://bbs.littlelan.cn
|
||||
const getBaseUrl = () => {
|
||||
@@ -74,37 +73,27 @@ interface JwtPayload {
|
||||
// API 客户端类
|
||||
class ApiClient {
|
||||
private baseUrl: string;
|
||||
private navigation: any = null;
|
||||
private expoRouter: any = null;
|
||||
private verificationModalShown = false;
|
||||
// 刷新锁:防止并发刷新
|
||||
private refreshLock: Promise<boolean> | null = null;
|
||||
|
||||
constructor(baseUrl: string) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
setExpoRouter(router: any) {
|
||||
this.expoRouter = router;
|
||||
}
|
||||
|
||||
private handleVerificationRequired() {
|
||||
if (this.verificationModalShown) return;
|
||||
this.verificationModalShown = true;
|
||||
if (this.expoRouter) {
|
||||
this.expoRouter.push(hrefVerificationGuide());
|
||||
}
|
||||
eventBus.emit({ type: 'SHOW_VERIFICATION_MODAL' });
|
||||
setTimeout(() => {
|
||||
this.verificationModalShown = false;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 设置导航对象(用于处理401跳转)
|
||||
setNavigation(navigation: any) {
|
||||
this.navigation = navigation;
|
||||
private navigateToLogin() {
|
||||
eventBus.emit({ type: 'NAVIGATE', payload: { path: '/(auth)/login' } });
|
||||
eventBus.emit({ type: 'AUTH_LOGOUT' });
|
||||
}
|
||||
|
||||
// 解析 JWT token 获取 payload
|
||||
private parseJwt(token: string): JwtPayload | null {
|
||||
try {
|
||||
const parts = token.split('.');
|
||||
@@ -208,19 +197,10 @@ class ApiClient {
|
||||
if (this.isTokenExpiringSoon(token)) {
|
||||
const refreshed = await this.refreshToken();
|
||||
if (!refreshed) {
|
||||
// 刷新失败,清除 token 并跳转登录
|
||||
await this.clearToken();
|
||||
if (this.navigation) {
|
||||
this.navigation.dispatch(
|
||||
CommonActions.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Login' }],
|
||||
})
|
||||
);
|
||||
}
|
||||
this.navigateToLogin();
|
||||
throw new ApiError(401, '登录已过期,请重新登录');
|
||||
}
|
||||
// 刷新成功,使用新 token
|
||||
const newToken = await this.getToken();
|
||||
if (newToken) {
|
||||
headers['Authorization'] = `Bearer ${newToken}`;
|
||||
@@ -246,23 +226,13 @@ class ApiClient {
|
||||
|
||||
// 处理 401 未授权
|
||||
if (response.status === 401) {
|
||||
// 尝试刷新 token
|
||||
const refreshed = await this.refreshToken();
|
||||
if (!refreshed) {
|
||||
// 刷新失败,清除 token 并跳转登录
|
||||
await this.clearToken();
|
||||
if (this.navigation) {
|
||||
this.navigation.dispatch(
|
||||
CommonActions.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Login' }],
|
||||
})
|
||||
);
|
||||
}
|
||||
this.navigateToLogin();
|
||||
throw new ApiError(401, '登录已过期,请重新登录');
|
||||
}
|
||||
|
||||
// 刷新成功后重试请求
|
||||
return this.request(method, path, params, body);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user