emote.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. const _ = require('lodash')
  2. const Mutex = require('promise-mutex')
  3. const log = require('../util/log')
  4. const MAX_EMOTES_IN_GUILD = 50
  5. class EmoteStore {
  6. constructor(game, guildIDs) {
  7. this.game = game
  8. this.guildIDs = guildIDs
  9. this.emotes = new Map() // id -> Emoji
  10. this.mutex = new Mutex()
  11. log.info(
  12. `Emote store capacity = ${this.guildIDs.length * MAX_EMOTES_IN_GUILD}`
  13. )
  14. if (this.guildIDs.length === 0) {
  15. throw 'Need at least one emote store server'
  16. }
  17. }
  18. randomClient() {
  19. return _.sample(this.game.clientPool)
  20. }
  21. // Cleans up each emote-storage guild, by removing all channels and emotes
  22. // present there. RIP.
  23. async cleanUp() {
  24. await Promise.all(
  25. this.guildIDs.map(guildID => {
  26. const guild = this.randomClient().guilds.get(guildID)
  27. return Promise.all([
  28. ...guild.channels.map(c => c.delete()),
  29. ...guild.emojis.map(e => guild.deleteEmoji(e)),
  30. ])
  31. })
  32. )
  33. }
  34. // Finds a guild with emote slots available. If there are none, deletes an
  35. // old emote from a guild.
  36. async findGuildForNewEmote(makeSlots = false) {
  37. for (const guildID of _.shuffle(this.guildIDs)) {
  38. const guild = this.randomClient().guilds.get(guildID)
  39. if (guild.emojis.size === MAX_EMOTES_IN_GUILD) {
  40. // Full, make a slot
  41. if (makeSlots) {
  42. const emoteToDel = guild.emojis.random()
  43. this.emotes.delete(emoteToDel.name)
  44. await guild.deleteEmoji(emoteToDel)
  45. }
  46. } else {
  47. // Has slots, use it
  48. return guild
  49. }
  50. }
  51. return this.findGuildForNewEmote(true) // Make slots this time
  52. }
  53. // Gets an emote by name, uploading it if it isn't found. Returns an Emoji.
  54. async get(name, graphic) {
  55. // Don't upload it if it's already there.
  56. if (this.emotes.has(name)) {
  57. return this.emotes.get(name)
  58. }
  59. // Upload it.
  60. let emote
  61. await this.mutex.lock(async () => {
  62. const guild = await this.findGuildForNewEmote()
  63. emote = await guild.createEmoji(graphic, name)
  64. })
  65. this.emotes.set(name, emote)
  66. return emote
  67. }
  68. }
  69. module.exports = EmoteStore