Files
frontend/src/stores/conversationListSources.ts

115 lines
3.4 KiB
TypeScript
Raw Normal View History

/**
* SQLite MessageManager
*/
import { ConversationResponse } from '../types/dto';
import { messageService } from '../services/messageService';
import { getConversationListCache } from '../services/database';
export const CONVERSATION_LIST_PAGE_SIZE = 20;
/** 单次拉取结果(一页或一批) */
export interface ConversationListPage {
items: ConversationResponse[];
/** 在当前源上是否还能再 loadNext 一页 */
hasMore: boolean;
}
/**
* restart loadNext
*/
export interface IConversationListPagedSource {
restart(): void;
loadNext(): Promise<ConversationListPage>;
/** 至少成功 loadNext 过一次且仍有下一页时为 true */
readonly hasMore: boolean;
}
/**
* offset cursor
* messageService.fetchRemoteConversationListPage
*/
export class NetworkRemoteConversationListPagedSource implements IConversationListPagedSource {
private nextPage = 1;
private nextCursor: string | null = null;
private hasMoreAfterLastLoad = false;
private loadedOnce = false;
private readonly pageSize: number;
private readonly mode: RemoteConversationListSourceKind;
constructor(
mode: RemoteConversationListSourceKind,
pageSize: number = CONVERSATION_LIST_PAGE_SIZE
) {
this.mode = mode;
this.pageSize = pageSize;
}
restart(): void {
this.nextPage = 1;
this.nextCursor = null;
this.hasMoreAfterLastLoad = false;
this.loadedOnce = false;
}
get hasMore(): boolean {
return this.loadedOnce && this.hasMoreAfterLastLoad;
}
async loadNext(): Promise<ConversationListPage> {
const result = await messageService.fetchRemoteConversationListPage({
mode: this.mode,
pageSize: this.pageSize,
...(this.mode === 'offset'
? { page: this.nextPage }
: { cursor: this.nextCursor }),
});
this.hasMoreAfterLastLoad = result.hasMore;
if (this.mode === 'offset') {
this.nextPage = result.nextPage ?? this.nextPage + 1;
} else {
this.nextCursor = result.nextCursor ?? null;
}
this.loadedOnce = true;
return { items: result.items, hasMore: result.hasMore };
}
}
/** SQLite 会话列表缓存(单批,无后续页) */
export class SqliteConversationListPagedSource implements IConversationListPagedSource {
private consumed = false;
restart(): void {
this.consumed = false;
}
get hasMore(): boolean {
return false;
}
async loadNext(): Promise<ConversationListPage> {
if (this.consumed) {
return { items: [], hasMore: false };
}
this.consumed = true;
try {
const items = await getConversationListCache();
return { items, hasMore: false };
} catch (e) {
console.warn('[SqliteConversationListPagedSource] 读取会话列表缓存失败:', e);
return { items: [], hasMore: false };
}
}
}
/** 远端会话列表分页策略 */
export type RemoteConversationListSourceKind = 'cursor' | 'offset';
export function createRemoteConversationListSource(
kind: RemoteConversationListSourceKind,
pageSize: number = CONVERSATION_LIST_PAGE_SIZE
): IConversationListPagedSource {
return new NetworkRemoteConversationListPagedSource(kind, pageSize);
}