'use strict'; // ============================================================================ // User // ============================================================================ import {SourcedSet} from 'utilities/object'; import type Chat from '.'; import type Room from './room'; import type { BadgeAssignment } from './types'; export default class User { // Parent manager: Chat; room: Room | null; // State destroyed: boolean = false; _id: string | null; _login: string | null = null; // Storage emote_sets: SourcedSet | null; badges: SourcedSet | null; constructor(manager: Chat, room: Room | null, id: string | null, login: string | null) { this.manager = manager; this.room = room; this.emote_sets = null; this.badges = null; this._id = id; this.login = login; if ( id ) (room ?? manager).user_ids[id] = this; } destroy() { this.destroyed = true; if ( this.emote_sets ) { for(const set_id of this.emote_sets._cache) this.manager.emotes.unrefSet(set_id); this.emote_sets = null; } // Badges are not referenced, so we can just dump them all. if ( this.badges ) this.badges = null; const parent = this.room || this.manager; if ( parent ) { if ( this._login && parent.users && parent.users[this._login] === this ) parent.users[this._login] = null; if ( parent.user_ids && parent.user_ids[this._id] === this ) parent.user_ids[this._id] = null; } } merge(other: User) { if ( ! this.login && other.login ) this.login = other.login; if ( other.emote_sets ) for(const [provider, sets] of other.emote_sets.iterateSources()) { for(const set_id of sets) this.addSet(provider, set_id); } if ( other.badges ) for(const [provider, badges] of other.badges.iterateSources()) { for(const badge of badges) this.addBadge(provider, badge.id, badge); } } _unloadAddon(addon_id: string) { // TODO: This return 0; } get id() { return this._id; } get login() { return this._login; } set login(val) { if ( this._login === val ) return; const obj = this.room || this.manager; if ( this._login ) { const old_user = obj.users[this._login]; if ( old_user === this ) obj.users[this._login] = null; } this._login = val; if ( ! val ) return; const old_user = obj.users[val]; if ( old_user && old_user !== this ) old_user.login = null; // Make sure we didn't have a funky loop thing happen. this._login = val; obj.users[val] = this; } // ======================================================================== // Add Badges // ======================================================================== addBadge(provider: string, badge_id: string, data?: BadgeAssignment) { if ( this.destroyed ) return false; if ( typeof badge_id === 'number' ) badge_id = `${badge_id}`; if ( data ) data.id = badge_id; else data = {id: badge_id}; if ( ! this.badges ) this.badges = new SourcedSet; const existing = this.badges.get(provider); if ( existing ) for(const old_b of existing) if ( old_b.id == badge_id ) { Object.assign(old_b, data); return false; } this.badges.push(provider, data); //this.manager.badges.refBadge(badge_id); return true; } getBadge(badge_id: string) { if ( this.badges ) for(const badge of this.badges._cache) if ( badge.id == badge_id ) return badge; return null; } removeBadge(provider: string, badge_id: string) { if ( ! this.badges ) return false; const existing = this.badges.get(provider); if ( existing ) for(const old_b of existing) if ( old_b.id == badge_id ) { this.badges.remove(provider, old_b); //this.manager.badges.unrefBadge(badge_id); return true; } return false; } removeAllBadges(provider: string) { if ( ! this.badges ) return false; if ( ! this.badges.has(provider) ) return false; // Just yeet them all since we don't ref badges. this.badges.delete(provider); return true; } // ======================================================================== // Emote Sets // ======================================================================== addSet(provider: string, set_id: string, data?: unknown) { if ( this.destroyed ) return; if ( ! this.emote_sets ) this.emote_sets = new SourcedSet; if ( typeof set_id === 'number' ) set_id = `${set_id}`; let changed = false, added = false; if ( ! this.emote_sets.sourceIncludes(provider, set_id) ) { changed = ! this.emote_sets.includes(set_id); this.emote_sets.push(provider, set_id); added = true; } if ( data ) this.manager.emotes.loadSetData(set_id, data); if ( changed ) { this.manager.emotes.refSet(set_id); this.manager.emotes.emit(':update-user-sets', this, provider, set_id, true); } return added; } removeAllSets(provider: string) { if ( ! this.emote_sets ) return false; const sets = this.emote_sets.get(provider); if ( ! Array.isArray(sets) || ! sets.length ) return false; for(const set_id of sets) this.removeSet(provider, set_id); return true; } removeSet(provider: string, set_id: string) { if ( ! this.emote_sets ) return; if ( typeof set_id === 'number' ) set_id = `${set_id}`; if ( this.emote_sets.sourceIncludes(provider, set_id) ) { this.emote_sets.remove(provider, set_id); if ( ! this.emote_sets.includes(set_id) ) { this.manager.emotes.unrefSet(set_id); this.manager.emotes.emit(':update-user-sets', this, provider, set_id, false); } return true; } return false; } }