UNPKG

@river-build/sdk

Version:

For more details, visit the following resources:

96 lines 4.2 kB
import { dlog } from '@river-build/dlog'; // this is a hack to prevent too much cpu usage from spamming the client with too many decrypted names // temporary until we move encrypted user and display names to the user metadata stream const MAX_DECRYPTED_NAMES_PER_STREAM = 50; const textDecoder = new TextDecoder(); export class MemberMetadata_DisplayNames { log = dlog('csb:streams:displaynames'); decryptionDispatchCount = 0; streamId; userIdToEventId = new Map(); plaintextDisplayNames = new Map(); displayNameEvents = new Map(); constructor(streamId) { this.streamId = streamId; } addEncryptedData(eventId, encryptedData, userId, pending = true, cleartext, encryptionEmitter, stateEmitter) { this.removeEventForUserId(userId); this.addEventForUserId(userId, eventId, encryptedData, pending); if (cleartext) { this.plaintextDisplayNames.set(userId, typeof cleartext === 'string' ? cleartext : textDecoder.decode(cleartext)); } else if (this.decryptionDispatchCount < MAX_DECRYPTED_NAMES_PER_STREAM) { this.decryptionDispatchCount++; // Clear the plaintext display name for this user on name change this.plaintextDisplayNames.delete(userId); encryptionEmitter?.emit('newEncryptedContent', this.streamId, eventId, { kind: 'text', content: encryptedData, }); } this.emitDisplayNameUpdated(eventId, stateEmitter); } onConfirmEvent(eventId, emitter) { const event = this.displayNameEvents.get(eventId); if (!event) { return; } this.displayNameEvents.set(eventId, { ...event, pending: false }); // if we don't have the plaintext display name, no need to emit an event if (this.plaintextDisplayNames.has(event.userId)) { this.log(`'streamDisplayNameUpdated' for userId ${event.userId}`); this.emitDisplayNameUpdated(eventId, emitter); } } onDecryptedContent(eventId, content, emitter) { const event = this.displayNameEvents.get(eventId); if (!event) { return; } this.log(`setting display name ${content} for user ${event.userId}`); this.plaintextDisplayNames.set(event.userId, content); this.emitDisplayNameUpdated(eventId, emitter); } emitDisplayNameUpdated(eventId, emitter) { const event = this.displayNameEvents.get(eventId); if (!event) { return; } // no information to emit — we haven't decrypted the display name yet if (!this.plaintextDisplayNames.has(event.userId)) { return; } // depending on confirmation status, emit different events emitter?.emit(event.pending ? 'streamPendingDisplayNameUpdated' : 'streamDisplayNameUpdated', this.streamId, event.userId); } removeEventForUserId(userId) { // remove any traces of old events for this user const eventId = this.userIdToEventId.get(userId); if (!eventId) { this.log(`no existing displayName event for user ${userId}`); return; } const event = this.displayNameEvents.get(eventId); if (!event) { this.log(`no existing event for user ${userId} — this is a programmer error`); return; } this.displayNameEvents.delete(eventId); this.log(`deleted old event for user ${userId}`); } addEventForUserId(userId, eventId, encryptedData, pending) { // add to the userId -> eventId mapping for fast lookup later this.userIdToEventId.set(userId, eventId); this.displayNameEvents.set(eventId, { userId, encryptedData: encryptedData, pending: pending, }); } info(userId) { const displayName = this.plaintextDisplayNames.get(userId) ?? ''; const displayNameEncrypted = !this.plaintextDisplayNames.has(userId) && this.userIdToEventId.has(userId); return { displayName, displayNameEncrypted }; } } //# sourceMappingURL=memberMetadata_DisplayNames.js.map