Add debugging console
This commit is contained in:
@@ -18,7 +18,9 @@ import {
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
import { Action } from '@ngrx/store';
|
||||
import { Message } from '../../core/models/index';
|
||||
import type { DebuggingService } from '../../core/services';
|
||||
import { DatabaseService } from '../../core/services/database.service';
|
||||
import { trackDebuggingTaskFailure } from '../../core/helpers/debugging-helpers';
|
||||
import { WebRTCService } from '../../core/services/webrtc.service';
|
||||
import { AttachmentService } from '../../core/services/attachment.service';
|
||||
import { MessagesActions } from './messages.actions';
|
||||
@@ -39,6 +41,7 @@ export interface IncomingMessageContext {
|
||||
db: DatabaseService;
|
||||
webrtc: WebRTCService;
|
||||
attachments: AttachmentService;
|
||||
debugging: DebuggingService;
|
||||
currentUser: any;
|
||||
currentRoom: any;
|
||||
}
|
||||
@@ -256,7 +259,7 @@ function requestMissingImages(
|
||||
/** Saves an incoming chat message to DB and dispatches receiveMessage. */
|
||||
function handleChatMessage(
|
||||
event: any,
|
||||
{ db, currentUser }: IncomingMessageContext
|
||||
{ db, debugging, currentUser }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
const msg = event.message;
|
||||
|
||||
@@ -271,22 +274,43 @@ function handleChatMessage(
|
||||
if (isOwnMessage)
|
||||
return EMPTY;
|
||||
|
||||
db.saveMessage(msg);
|
||||
trackBackgroundOperation(
|
||||
db.saveMessage(msg),
|
||||
debugging,
|
||||
'Failed to persist incoming chat message',
|
||||
{
|
||||
channelId: msg.channelId || 'general',
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: msg.id,
|
||||
roomId: msg.roomId,
|
||||
senderId: msg.senderId
|
||||
}
|
||||
);
|
||||
|
||||
return of(MessagesActions.receiveMessage({ message: msg }));
|
||||
}
|
||||
|
||||
/** Applies a remote message edit to the local DB and store. */
|
||||
function handleMessageEdited(
|
||||
event: any,
|
||||
{ db }: IncomingMessageContext
|
||||
{ db, debugging }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
if (!event.messageId || !event.content)
|
||||
return EMPTY;
|
||||
|
||||
db.updateMessage(event.messageId, {
|
||||
content: event.content,
|
||||
editedAt: event.editedAt
|
||||
});
|
||||
trackBackgroundOperation(
|
||||
db.updateMessage(event.messageId, {
|
||||
content: event.content,
|
||||
editedAt: event.editedAt
|
||||
}),
|
||||
debugging,
|
||||
'Failed to persist incoming message edit',
|
||||
{
|
||||
editedAt: event.editedAt ?? null,
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: event.messageId
|
||||
}
|
||||
);
|
||||
|
||||
return of(
|
||||
MessagesActions.editMessageSuccess({
|
||||
@@ -300,12 +324,22 @@ function handleMessageEdited(
|
||||
/** Applies a remote message deletion to the local DB and store. */
|
||||
function handleMessageDeleted(
|
||||
event: any,
|
||||
{ db }: IncomingMessageContext
|
||||
{ db, debugging }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
if (!event.messageId)
|
||||
return EMPTY;
|
||||
|
||||
db.deleteMessage(event.messageId);
|
||||
trackBackgroundOperation(
|
||||
db.deleteMessage(event.messageId),
|
||||
debugging,
|
||||
'Failed to persist incoming message deletion',
|
||||
{
|
||||
deletedBy: event.deletedBy ?? null,
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: event.messageId
|
||||
}
|
||||
);
|
||||
|
||||
return of(
|
||||
MessagesActions.deleteMessageSuccess({ messageId: event.messageId })
|
||||
);
|
||||
@@ -314,24 +348,46 @@ function handleMessageDeleted(
|
||||
/** Saves an incoming reaction to DB and updates the store. */
|
||||
function handleReactionAdded(
|
||||
event: any,
|
||||
{ db }: IncomingMessageContext
|
||||
{ db, debugging }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
if (!event.messageId || !event.reaction)
|
||||
return EMPTY;
|
||||
|
||||
db.saveReaction(event.reaction);
|
||||
trackBackgroundOperation(
|
||||
db.saveReaction(event.reaction),
|
||||
debugging,
|
||||
'Failed to persist incoming reaction',
|
||||
{
|
||||
emoji: event.reaction.emoji,
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: event.messageId,
|
||||
reactionId: event.reaction.id
|
||||
}
|
||||
);
|
||||
|
||||
return of(MessagesActions.addReactionSuccess({ reaction: event.reaction }));
|
||||
}
|
||||
|
||||
/** Removes a reaction from DB and updates the store. */
|
||||
function handleReactionRemoved(
|
||||
event: any,
|
||||
{ db }: IncomingMessageContext
|
||||
{ db, debugging }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
if (!event.messageId || !event.oderId || !event.emoji)
|
||||
return EMPTY;
|
||||
|
||||
db.removeReaction(event.messageId, event.oderId, event.emoji);
|
||||
trackBackgroundOperation(
|
||||
db.removeReaction(event.messageId, event.oderId, event.emoji),
|
||||
debugging,
|
||||
'Failed to persist incoming reaction removal',
|
||||
{
|
||||
emoji: event.emoji,
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: event.messageId,
|
||||
oderId: event.oderId
|
||||
}
|
||||
);
|
||||
|
||||
return of(
|
||||
MessagesActions.removeReactionSuccess({
|
||||
messageId: event.messageId,
|
||||
@@ -442,12 +498,24 @@ function handleSyncRequest(
|
||||
/** Merges a full message dump from a peer into the local DB and store. */
|
||||
function handleSyncFull(
|
||||
event: any,
|
||||
{ db }: IncomingMessageContext
|
||||
{ db, debugging }: IncomingMessageContext
|
||||
): Observable<Action> {
|
||||
if (!event.messages || !Array.isArray(event.messages))
|
||||
return EMPTY;
|
||||
|
||||
event.messages.forEach((msg: Message) => db.saveMessage(msg));
|
||||
event.messages.forEach((msg: Message) => {
|
||||
trackBackgroundOperation(
|
||||
db.saveMessage(msg),
|
||||
debugging,
|
||||
'Failed to persist full-sync message batch item',
|
||||
{
|
||||
fromPeerId: event.fromPeerId ?? null,
|
||||
messageId: msg.id,
|
||||
roomId: msg.roomId
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return of(MessagesActions.syncMessages({ messages: event.messages }));
|
||||
}
|
||||
|
||||
@@ -493,3 +561,12 @@ export function dispatchIncomingMessage(
|
||||
|
||||
return handler ? handler(event, ctx) : EMPTY;
|
||||
}
|
||||
|
||||
function trackBackgroundOperation(
|
||||
task: Promise<unknown> | unknown,
|
||||
debugging: DebuggingService,
|
||||
message: string,
|
||||
payload: Record<string, unknown>
|
||||
): void {
|
||||
trackDebuggingTaskFailure(task, debugging, 'messages', message, payload);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import { RoomsActions } from '../rooms/rooms.actions';
|
||||
import { selectMessagesSyncing } from './messages.selectors';
|
||||
import { selectCurrentRoom } from '../rooms/rooms.selectors';
|
||||
import { DatabaseService } from '../../core/services/database.service';
|
||||
import { DebuggingService } from '../../core/services/debugging.service';
|
||||
import { WebRTCService } from '../../core/services/webrtc.service';
|
||||
import {
|
||||
INVENTORY_LIMIT,
|
||||
@@ -55,6 +56,7 @@ export class MessagesSyncEffects {
|
||||
private readonly actions$ = inject(Actions);
|
||||
private readonly store = inject(Store);
|
||||
private readonly db = inject(DatabaseService);
|
||||
private readonly debugging = inject(DebuggingService);
|
||||
private readonly webrtc = inject(WebRTCService);
|
||||
|
||||
/** Tracks whether the last sync cycle found no new messages. */
|
||||
@@ -135,8 +137,12 @@ export class MessagesSyncEffects {
|
||||
type: 'chat-inventory-request',
|
||||
roomId: activeRoom.id
|
||||
} as any);
|
||||
} catch {
|
||||
/* peer may have disconnected */
|
||||
} catch (error) {
|
||||
this.debugging.warn('messages', 'Failed to kick off room sync for peer', {
|
||||
error,
|
||||
peerId: pid,
|
||||
roomId: activeRoom.id
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -181,15 +187,24 @@ export class MessagesSyncEffects {
|
||||
type: 'chat-inventory-request',
|
||||
roomId: room.id
|
||||
} as any);
|
||||
} catch {
|
||||
/* peer may have disconnected */
|
||||
} catch (error) {
|
||||
this.debugging.warn('messages', 'Failed to request peer inventory during sync poll', {
|
||||
error,
|
||||
peerId: pid,
|
||||
roomId: room.id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return MessagesActions.startSync();
|
||||
}),
|
||||
catchError(() => {
|
||||
catchError((error) => {
|
||||
this.lastSyncClean = false;
|
||||
this.debugging.warn('messages', 'Periodic sync poll failed', {
|
||||
error,
|
||||
roomId: room.id
|
||||
});
|
||||
|
||||
return of(MessagesActions.syncComplete());
|
||||
})
|
||||
);
|
||||
|
||||
@@ -32,6 +32,8 @@ import { MessagesActions } from './messages.actions';
|
||||
import { selectCurrentUser } from '../users/users.selectors';
|
||||
import { selectCurrentRoom } from '../rooms/rooms.selectors';
|
||||
import { DatabaseService } from '../../core/services/database.service';
|
||||
import { reportDebuggingError, trackDebuggingTaskFailure } from '../../core/helpers/debugging-helpers';
|
||||
import { DebuggingService } from '../../core/services';
|
||||
import { WebRTCService } from '../../core/services/webrtc.service';
|
||||
import { TimeSyncService } from '../../core/services/time-sync.service';
|
||||
import { AttachmentService } from '../../core/services/attachment.service';
|
||||
@@ -44,6 +46,7 @@ export class MessagesEffects {
|
||||
private readonly actions$ = inject(Actions);
|
||||
private readonly store = inject(Store);
|
||||
private readonly db = inject(DatabaseService);
|
||||
private readonly debugging = inject(DebuggingService);
|
||||
private readonly webrtc = inject(WebRTCService);
|
||||
private readonly timeSync = inject(TimeSyncService);
|
||||
private readonly attachments = inject(AttachmentService);
|
||||
@@ -97,7 +100,17 @@ export class MessagesEffects {
|
||||
replyToId
|
||||
};
|
||||
|
||||
this.db.saveMessage(message);
|
||||
this.trackBackgroundOperation(
|
||||
this.db.saveMessage(message),
|
||||
'Failed to persist outgoing chat message',
|
||||
{
|
||||
channelId: message.channelId,
|
||||
contentLength: message.content.length,
|
||||
messageId: message.id,
|
||||
roomId: message.roomId
|
||||
}
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({ type: 'chat-message',
|
||||
message });
|
||||
|
||||
@@ -131,8 +144,16 @@ export class MessagesEffects {
|
||||
|
||||
const editedAt = this.timeSync.now();
|
||||
|
||||
this.db.updateMessage(messageId, { content,
|
||||
editedAt });
|
||||
this.trackBackgroundOperation(
|
||||
this.db.updateMessage(messageId, { content,
|
||||
editedAt }),
|
||||
'Failed to persist edited chat message',
|
||||
{
|
||||
contentLength: content.length,
|
||||
editedAt,
|
||||
messageId
|
||||
}
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({ type: 'message-edited',
|
||||
messageId,
|
||||
@@ -171,7 +192,12 @@ export class MessagesEffects {
|
||||
return of(MessagesActions.deleteMessageFailure({ error: 'Cannot delete others messages' }));
|
||||
}
|
||||
|
||||
this.db.updateMessage(messageId, { isDeleted: true });
|
||||
this.trackBackgroundOperation(
|
||||
this.db.updateMessage(messageId, { isDeleted: true }),
|
||||
'Failed to persist message deletion',
|
||||
{ messageId }
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({ type: 'message-deleted',
|
||||
messageId });
|
||||
|
||||
@@ -204,7 +230,15 @@ export class MessagesEffects {
|
||||
return of(MessagesActions.deleteMessageFailure({ error: 'Permission denied' }));
|
||||
}
|
||||
|
||||
this.db.updateMessage(messageId, { isDeleted: true });
|
||||
this.trackBackgroundOperation(
|
||||
this.db.updateMessage(messageId, { isDeleted: true }),
|
||||
'Failed to persist admin message deletion',
|
||||
{
|
||||
deletedBy: currentUser.id,
|
||||
messageId
|
||||
}
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({ type: 'message-deleted',
|
||||
messageId,
|
||||
deletedBy: currentUser.id });
|
||||
@@ -235,7 +269,17 @@ export class MessagesEffects {
|
||||
timestamp: this.timeSync.now()
|
||||
};
|
||||
|
||||
this.db.saveReaction(reaction);
|
||||
this.trackBackgroundOperation(
|
||||
this.db.saveReaction(reaction),
|
||||
'Failed to persist reaction',
|
||||
{
|
||||
emoji,
|
||||
messageId,
|
||||
reactionId: reaction.id,
|
||||
userId: currentUser.id
|
||||
}
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({ type: 'reaction-added',
|
||||
messageId,
|
||||
reaction });
|
||||
@@ -254,7 +298,16 @@ export class MessagesEffects {
|
||||
if (!currentUser)
|
||||
return EMPTY;
|
||||
|
||||
this.db.removeReaction(messageId, currentUser.id, emoji);
|
||||
this.trackBackgroundOperation(
|
||||
this.db.removeReaction(messageId, currentUser.id, emoji),
|
||||
'Failed to persist reaction removal',
|
||||
{
|
||||
emoji,
|
||||
messageId,
|
||||
userId: currentUser.id
|
||||
}
|
||||
);
|
||||
|
||||
this.webrtc.broadcastMessage({
|
||||
type: 'reaction-removed',
|
||||
messageId,
|
||||
@@ -286,18 +339,43 @@ export class MessagesEffects {
|
||||
mergeMap(([
|
||||
event,
|
||||
currentUser,
|
||||
currentRoom]: [any, any, any
|
||||
currentRoom
|
||||
]) => {
|
||||
const ctx: IncomingMessageContext = {
|
||||
db: this.db,
|
||||
webrtc: this.webrtc,
|
||||
attachments: this.attachments,
|
||||
debugging: this.debugging,
|
||||
currentUser,
|
||||
currentRoom
|
||||
};
|
||||
|
||||
return dispatchIncomingMessage(event, ctx);
|
||||
return dispatchIncomingMessage(event, ctx).pipe(
|
||||
catchError((error) => {
|
||||
const eventRecord = event as unknown as Record<string, unknown>;
|
||||
const messageRecord = (eventRecord['message'] && typeof eventRecord['message'] === 'object' && !Array.isArray(eventRecord['message']))
|
||||
? eventRecord['message'] as Record<string, unknown>
|
||||
: null;
|
||||
|
||||
reportDebuggingError(this.debugging, 'messages', 'Failed to process incoming peer message', {
|
||||
eventType: typeof eventRecord['type'] === 'string' ? eventRecord['type'] : 'unknown',
|
||||
fromPeerId: typeof eventRecord['fromPeerId'] === 'string' ? eventRecord['fromPeerId'] : null,
|
||||
messageId: typeof eventRecord['messageId'] === 'string'
|
||||
? eventRecord['messageId']
|
||||
: (typeof messageRecord?.['id'] === 'string' ? messageRecord['id'] : null),
|
||||
roomId: typeof eventRecord['roomId'] === 'string'
|
||||
? eventRecord['roomId']
|
||||
: (typeof messageRecord?.['roomId'] === 'string' ? messageRecord['roomId'] : null)
|
||||
}, error);
|
||||
|
||||
return EMPTY;
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
private trackBackgroundOperation(task: Promise<unknown> | unknown, message: string, payload: Record<string, unknown>): void {
|
||||
trackDebuggingTaskFailure(task, this.debugging, 'messages', message, payload);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user