Skip to content

Commit a366105

Browse files
committed
fix(chat): real-time message delivery between users
- Filter out ack frames without message body in onMessage/onEditMessage to prevent Observable crash and silent subscription death - Add currentChatId signal with type-safe string comparison to prevent cross-chat message leaks - Guard mapChatMessage from null/undefined inputs
1 parent 4af33fc commit a366105

4 files changed

Lines changed: 19 additions & 12 deletions

File tree

projects/social_platform/src/app/api/chat/facades/chat-direct-info.service.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ export class ChatDirectInfoService {
7070
this.route.data
7171
.pipe(
7272
map(r => r["data"]),
73-
tap(chat => this.chat.set(chat)),
73+
tap(chat => {
74+
this.chat.set(chat);
75+
this.chatDirectUIInfoService.currentChatId.set(this.getChatId());
76+
}),
7477
switchMap(() => this.fetchMessages(type)),
7578
takeUntil(this.destroy$)
7679
)

projects/social_platform/src/app/api/chat/facades/ui/chat-direct-ui-info.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export class ChatDirectUIInfoService {
3030

3131
/** ID текущего пользователя */
3232
readonly currentUserId = signal<number | undefined>(undefined);
33+
readonly currentChatId = signal<string | undefined>(undefined);
3334

3435
/** Флаг процесса загрузки сообщений */
3536
readonly fetching = signal<boolean>(false);
@@ -79,8 +80,8 @@ export class ChatDirectUIInfoService {
7980
}
8081

8182
applyMessageEvent(result: OnChatMessageDto): void {
82-
// Бэк иногда шлёт ack-фрейм без поля message — игнорим, чтобы не пушить undefined в список.
8383
if (!result?.message) return;
84+
if (String(result.chatId) !== this.currentChatId()) return;
8485
this.messages.update(list => [...list, result.message]);
8586
}
8687

projects/social_platform/src/app/infrastructure/repository/chat/chat-realtime.repository.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
TypingInChatEventDto,
1313
} from "@domain/chat/chat.model";
1414
import { plainToInstance } from "class-transformer";
15-
import { map } from "rxjs";
15+
import { filter, map } from "rxjs";
1616
import { WebsocketService } from "@core/public-api";
1717
import { SnackbarService } from "@ui/services/snackbar/snackbar.service";
1818
import { mapChatMessage } from "./chat.repository";
@@ -41,7 +41,7 @@ export class ChatRealtimeRepository implements ChatRealtimePort {
4141
}
4242

4343
editMessage(message: Parameters<ChatRealtimePort["editMessage"]>[0]): void {
44-
this.chatWsAdapter.editMessage(message);
44+
this.chatWsAdapter.editMessage(message)
4545
}
4646

4747
deleteMessage(message: Parameters<ChatRealtimePort["deleteMessage"]>[0]): void {
@@ -57,16 +57,18 @@ export class ChatRealtimeRepository implements ChatRealtimePort {
5757
}
5858

5959
onMessage() {
60-
return this.chatWsAdapter.onMessage().pipe(
61-
map(message => plainToInstance(OnChatMessageDto, message)),
62-
map(dto => ({ ...dto, message: mapChatMessage(dto.message) } as OnChatMessageDto))
63-
);
64-
}
60+
return this.chatWsAdapter.onMessage().pipe(
61+
map(message => plainToInstance(OnChatMessageDto, message)),
62+
filter(dto => !!dto.message),
63+
map(dto => ({ ...dto, message: mapChatMessage(dto.message)! } as OnChatMessageDto))
64+
);
65+
}
6566

6667
onEditMessage() {
6768
return this.chatWsAdapter.onEditMessage().pipe(
6869
map(message => plainToInstance(OnEditChatMessageDto, message)),
69-
map(dto => ({ ...dto, message: mapChatMessage(dto.message) } as OnEditChatMessageDto))
70+
filter(dto => !!dto.message),
71+
map(dto => ({ ...dto, message: mapChatMessage(dto.message)! } as OnEditChatMessageDto))
7072
);
7173
}
7274

projects/social_platform/src/app/infrastructure/repository/chat/chat.repository.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export class ChatRepository implements ChatRepositoryPort {
1717
return this.chatHttpAdapter.loadMessages(id, type, offset, limit).pipe(
1818
map(page => ({
1919
...page,
20-
results: page.results.map(mapChatMessage),
20+
results: page.results.map(mapChatMessage).filter((message): message is ChatMessage => message !== null),
2121
}))
2222
);
2323
}
@@ -33,7 +33,8 @@ export class ChatRepository implements ChatRepositoryPort {
3333
}
3434
}
3535

36-
export function mapChatMessage(message: ChatMessage): ChatMessage {
36+
export function mapChatMessage(message: ChatMessage | null | undefined): ChatMessage | null {
37+
if (!message) return null;
3738
return {
3839
...message,
3940
author: message.author ? userFromRaw(message.author) : message.author,

0 commit comments

Comments
 (0)