feat: Add emoji and alot of other fixes

This commit is contained in:
2026-06-05 05:40:18 +02:00
parent ca069e2f61
commit 6865147e8f
72 changed files with 3885 additions and 413 deletions
@@ -0,0 +1,127 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { Injectable, inject } from '@angular/core';
import { createEffect } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import {
EMPTY,
from,
merge,
Observable
} from 'rxjs';
import {
distinctUntilChanged,
map,
mergeMap
} from 'rxjs/operators';
import { selectCurrentUser } from '../../../store/users/users.selectors';
import {
ChatEvent,
CustomEmoji,
CustomEmojiSummaryItem,
CustomEmojiTransferManifest
} from '../../../shared-kernel';
import { RealtimeSessionFacade } from '../../../core/realtime';
import { CustomEmojiService } from './custom-emoji.service';
@Injectable()
export class CustomEmojiSyncEffects {
private readonly customEmoji = inject(CustomEmojiService);
private readonly store = inject(Store);
private readonly webrtc = inject(RealtimeSessionFacade);
private readonly incomingEvents$ = merge(
this.webrtc.onMessageReceived,
this.webrtc.onSignalingMessage as Observable<ChatEvent>
);
currentUserLoad$ = createEffect(
() => this.store.select(selectCurrentUser).pipe(
map((user) => user?.id ?? null),
distinctUntilChanged(),
mergeMap((userId) => from(this.customEmoji.loadForUser(userId)).pipe(mergeMap(() => EMPTY)))
),
{ dispatch: false }
);
peerConnectedSummary$ = createEffect(
() => this.webrtc.onPeerConnected.pipe(
mergeMap((peerId) => from(this.customEmoji.sendSummaryToPeer(peerId)).pipe(mergeMap(() => EMPTY)))
),
{ dispatch: false }
);
incomingCustomEmojiEvents$ = createEffect(
() => this.incomingEvents$.pipe(
mergeMap((event) => {
if (event.type === 'message' || event.type === 'chat-message') {
if (!event.fromPeerId || typeof event.message?.content !== 'string') {
return EMPTY;
}
return from(this.customEmoji.requestMissingFromMessageContent(event.fromPeerId, event.message.content)).pipe(mergeMap(() => EMPTY));
}
if (event.type === 'chat-sync-batch' || event.type === 'chat-sync-full') {
if (!event.fromPeerId || !Array.isArray(event.messages)) {
return EMPTY;
}
return from(Promise.all(event.messages.map((message) => this.customEmoji.requestMissingFromMessageContent(
event.fromPeerId as string,
message.content
)))).pipe(mergeMap(() => EMPTY));
}
switch (event.type) {
case 'custom-emoji-summary': {
if (!event.fromPeerId || !Array.isArray(event.customEmojiSummaries)) {
return EMPTY;
}
const ids = this.customEmoji.missingFromSummary(event.customEmojiSummaries as CustomEmojiSummaryItem[]);
if (ids.length === 0) {
return EMPTY;
}
this.webrtc.sendToPeer(event.fromPeerId, {
type: 'custom-emoji-request',
ids
});
return EMPTY;
}
case 'custom-emoji-request':
if (!event.fromPeerId || !Array.isArray(event.ids)) {
return EMPTY;
}
return from(this.customEmoji.sendRequestedToPeer(event.fromPeerId, event.ids)).pipe(mergeMap(() => EMPTY));
case 'custom-emoji-full':
if (event.customEmoji) {
return from(this.customEmoji.saveRemoteEmoji(event.customEmoji as CustomEmoji)).pipe(mergeMap(() => EMPTY));
}
if (!event.customEmojiTransfer || typeof event.total !== 'number') {
return EMPTY;
}
this.customEmoji.receiveTransferStart(event.customEmojiTransfer as CustomEmojiTransferManifest, event.total);
return EMPTY;
case 'custom-emoji-chunk':
if (!event.customEmojiId || typeof event.index !== 'number' || typeof event.total !== 'number' || typeof event.data !== 'string') {
return EMPTY;
}
return from(this.customEmoji.receiveTransferChunk(event.customEmojiId, event.index, event.total, event.data)).pipe(mergeMap(() => EMPTY));
default:
return EMPTY;
}
})
),
{ dispatch: false }
);
}