fix(chat): isolate pending flows and cancel stale requests

This commit is contained in:
2026-07-17 19:22:01 +08:00
parent 2fc312b5c7
commit 8bb1e21886
27 changed files with 501 additions and 92 deletions
@@ -1,4 +1,8 @@
import type { UnlockPrivateMessageInput } from "@/data/repositories/interfaces";
import type {
ChatRequestOptions,
ChatSendOptions,
UnlockPrivateMessageInput,
} from "@/data/repositories/interfaces";
import {
ChatHistoryResponse,
ChatSendResponse,
@@ -17,7 +21,7 @@ export class ChatRemoteDataSource {
async sendMessage(
characterId: string,
message: string,
options?: { image?: string; useWebSocket?: boolean },
options?: ChatSendOptions,
): Promise<Result<ChatSendResponse>> {
return Result.wrap(async () => {
const request = SendMessageRequestSchema.parse({
@@ -26,7 +30,7 @@ export class ChatRemoteDataSource {
image: options?.image ?? "",
useWebSocket: options?.useWebSocket ?? false,
});
return await this.api.sendMessage(request);
return await this.api.sendMessage(request, options);
});
}
@@ -34,23 +38,34 @@ export class ChatRemoteDataSource {
characterId: string,
limit = 50,
offset = 0,
options?: ChatRequestOptions,
): Promise<Result<ChatHistoryResponse>> {
return Result.wrap(() => this.api.getHistory(characterId, limit, offset));
return Result.wrap(() =>
this.api.getHistory(characterId, limit, offset, options),
);
}
async unlockPrivateMessage(
input: UnlockPrivateMessageInput,
options?: ChatRequestOptions,
): Promise<Result<UnlockPrivateResponse>> {
return Result.wrap(() =>
this.api.unlockPrivateMessage(UnlockPrivateRequestSchema.parse(input)),
this.api.unlockPrivateMessage(
UnlockPrivateRequestSchema.parse(input),
options,
),
);
}
async unlockHistory(
characterId: string,
options?: ChatRequestOptions,
): Promise<Result<UnlockHistoryResponse>> {
return Result.wrap(() =>
this.api.unlockHistory(UnlockHistoryRequestSchema.parse({ characterId })),
this.api.unlockHistory(
UnlockHistoryRequestSchema.parse({ characterId }),
options,
),
);
}
}
+9 -4
View File
@@ -1,6 +1,8 @@
import type {
CacheRemoteChatMediaInput,
ChatMediaLookupInput,
ChatRequestOptions,
ChatSendOptions,
IChatRepository,
UnlockPrivateMessageInput,
UnlockedPrivateMessageLocalPatch,
@@ -38,7 +40,7 @@ export class ChatRepository implements IChatRepository {
async sendMessage(
characterId: string,
message: string,
options?: { image?: string; useWebSocket?: boolean },
options?: ChatSendOptions,
): Promise<Result<ChatSendResponse>> {
return this.remote.sendMessage(characterId, message, options);
}
@@ -48,22 +50,25 @@ export class ChatRepository implements IChatRepository {
characterId: string,
limit = 50,
offset = 0,
options?: ChatRequestOptions,
): Promise<Result<ChatHistoryResponse>> {
return this.remote.getHistory(characterId, limit, offset);
return this.remote.getHistory(characterId, limit, offset, options);
}
/** 解锁单条历史付费 / 私密消息。 */
async unlockPrivateMessage(
input: UnlockPrivateMessageInput,
options?: ChatRequestOptions,
): Promise<Result<UnlockPrivateResponse>> {
return this.remote.unlockPrivateMessage(input);
return this.remote.unlockPrivateMessage(input, options);
}
/** 一键解锁历史锁定消息。 */
async unlockHistory(
characterId: string,
options?: ChatRequestOptions,
): Promise<Result<UnlockHistoryResponse>> {
return this.remote.unlockHistory(characterId);
return this.remote.unlockHistory(characterId, options);
}
/** 把本地缓存中的单条锁定消息标记为已解锁。 */
@@ -42,12 +42,21 @@ export interface UnlockPrivateMessageInput {
clientLockId?: string;
}
export interface ChatRequestOptions {
signal?: AbortSignal;
}
export interface ChatSendOptions extends ChatRequestOptions {
image?: string;
useWebSocket?: boolean;
}
export interface IChatRepository {
/** 发送一条消息。 */
sendMessage(
characterId: string,
message: string,
options?: { image?: string; useWebSocket?: boolean },
options?: ChatSendOptions,
): Promise<Result<ChatSendResponse>>;
/** 获取聊天历史,分页参数默认 limit=50, offset=0。 */
@@ -55,15 +64,20 @@ export interface IChatRepository {
characterId: string,
limit?: number,
offset?: number,
options?: ChatRequestOptions,
): Promise<Result<ChatHistoryResponse>>;
/** 解锁单条历史付费 / 私密消息。 */
unlockPrivateMessage(
input: UnlockPrivateMessageInput,
options?: ChatRequestOptions,
): Promise<Result<UnlockPrivateResponse>>;
/** 一键解锁历史锁定消息。 */
unlockHistory(characterId: string): Promise<Result<UnlockHistoryResponse>>;
unlockHistory(
characterId: string,
options?: ChatRequestOptions,
): Promise<Result<UnlockHistoryResponse>>;
/** 把本地缓存中的单条锁定消息标记为已解锁。 */
markPrivateMessageUnlockedInLocal(