UNPKG

@casual-simulation/aux-common

Version:
180 lines 5.38 kB
import { tagsOnBot, hasValue, calculateBotValue } from './BotCalculations'; import { Subject } from 'rxjs'; import { filter, startWith, map } from 'rxjs/operators'; /** * Defines an index that is optimized for looking up bots by their tags. */ export class BotIndex { get events() { let events = this.initialEvents(); return this._events.pipe(startWith(events), filter((e) => e.length > 0)); } initialEvents() { let bots = [...this._botMap.values()]; let events = bots.flatMap((b) => tagsOnBot(b).map((t) => ({ type: 'bot_tag_added', bot: b, tag: t, }))); return events; } constructor() { /** * The index events. */ this._events = new Subject(); this._batch = null; this._botMap = new Map(); this._tagMap = new Map(); } /** * Finds a list of bots that have the given tag. * @param tag The tag. */ findBotsWithTag(tag) { const list = this._botList(tag); return [...list.values()].map((id) => this._botMap.get(id)); } /** * Batches all the index events during the given function. * @param func The function. */ batch(func) { let batch = []; this._batch = batch; func(); if (batch.length > 0) { this._events.next(batch); } this._batch = null; return batch; } /** * Adds the given bots to the index. * @param bots The bots to add. */ addBots(bots) { let events = []; for (let bot of bots) { this._botMap.set(bot.id, bot); const tags = tagsOnBot(bot); for (let tag of tags) { let list = this._botList(tag); list.add(bot.id); events.push({ type: 'bot_tag_added', bot: bot, tag: tag, }); } } this._issueEvents(events); return events; } /** * Updates the given bots in the index by adding new tags and removing old tags. * @param bots The bot that were updated. */ updateBots(bots) { let events = []; for (let update of bots) { const bot = update.bot; const tags = update.tags; if (!bot || !tags) { continue; } let oldBot = this._botMap.get(bot.id); this._botMap.set(bot.id, bot); for (let tag of tags) { let list = this._botList(tag); let val = calculateBotValue(null, bot, tag); if (hasValue(val)) { if (!list.has(bot.id)) { list.add(bot.id); events.push({ type: 'bot_tag_added', bot: bot, tag: tag, }); } else { events.push({ type: 'bot_tag_updated', bot: bot, oldBot: oldBot, tag: tag, }); } } else { list.delete(bot.id); events.push({ type: 'bot_tag_removed', bot: bot, oldBot: oldBot, tag: tag, }); } } } this._issueEvents(events); return events; } /** * Removes the given bots from the index. * @param botIds The bots that were removed. */ removeBots(botIds) { let events = []; for (let botId of botIds) { const bot = this._botMap.get(botId); if (!bot) { continue; } this._botMap.delete(bot.id); const tags = tagsOnBot(bot); for (let tag of tags) { let list = this._botList(tag); list.delete(bot.id); events.push({ type: 'bot_tag_removed', bot: bot, oldBot: bot, tag: tag, }); } } this._issueEvents(events); return events; } /** * Watches the given tag for changes. * @param tag The tag to watch. */ watchTag(tag) { return this._events.pipe(map((events) => events.filter((e) => e.tag === tag)), filter((events) => events.length > 0), startWith(this.findBotsWithTag(tag).map((bot) => ({ type: 'bot_tag_added', bot: bot, tag: tag, })))); } _issueEvents(events) { if (events.length > 0) { if (this._batch !== null) { this._batch.push(...events); } else { this._events.next(events); } } } _botList(tag) { let list = this._tagMap.get(tag); if (!list) { list = new Set(); this._tagMap.set(tag, list); } return list; } } //# sourceMappingURL=BotIndex.js.map