Source: services/token-manager-pool.js

import TokenManager from './token-manager.js'

/** Gère l'assocation des token-manager au resource (layer, control, service...)
 * Permet de mutualiser les token-manager entre plusieurs resources
*/
export default class TokenManagerPool {
  /**
   * @ type {Map<String, {tokenManager: TokenManager, resources: Array<{resourceType: String, resourceId: String}>}>}
   */
  #tokenManagers = new Map()

  /**
   *
   * @param {String} resourceType type de resource (layer, control, service...)
   * @param {String} resourceId identifiant de la resource
   * @param {import("./token-manager").tokenOptions | String} tokenOptions options de gestion du token ou token en clair (historique)
  * @returns {TokenManager}
  */
  async addTokenSource (resourceType, resourceId, tokenOptions) {
    const tokenSourceOptions = typeof tokenOptions === 'object'
      ? {
          autoStart: true,
          ...tokenOptions,
        }
      : tokenOptions
    const autoStart = typeof tokenSourceOptions === 'string' ? true : tokenSourceOptions.autoStart
    const tokenManagerKey = this.#getTokenManagerKey(tokenSourceOptions)
    if (!this.#tokenManagers.has(tokenManagerKey)) {
      // si le token manager n'existe pas, on le crée
      const tokenManager = new TokenManager(tokenSourceOptions)
      if (autoStart) {
        await tokenManager.init()
      }
      this.#tokenManagers.set(tokenManagerKey, {
        tokenManager,
        resources: [{ resourceType, resourceId }],
      })
    } else {
      // on ajoute la resource à la liste des resources utilisant ce token manager
      const tokenManagerEntry = this.#tokenManagers.get(tokenManagerKey)
      tokenManagerEntry.resources.push({ resourceType, resourceId })
    }
    return this.#tokenManagers.get(tokenManagerKey).tokenManager
  }

  /**
   * supprime un token manager et toutes les resources qui l'utilisent
   * @param {import("./token-manager").tokenOptions | String} tokenOptions options de gestion du token ou token en clair (historique)
  * @returns {Boolean}
  */
  removeTokenSource (tokenOptions) {
    const tokenKey = this.#getTokenManagerKey(tokenOptions)
    return this.#tokenManagers.delete(tokenKey)
  }

  /**
   * Retire une source de la liste des resources utilisant un token manager, si plus aucune resource n'utilise ce token manager, on le supprime
   * @param {String} resourceType type de resource (layer, control, service...)
   * @param {String} resourceId identifiant de la resource
   * @param {Boolean} [removeTokenManagerIfNoResource=false] indique si le token manager doit être supprimé si aucune ressource ne l'utilise
   */
  removeResource (resourceType, resourceId, removeTokenManagerIfNoResource = false) {
    for (const [key, entry] of this.#tokenManagers.entries()) {
      const index = entry.resources.findIndex(r => r.resourceType === resourceType && r.resourceId === resourceId)
      if (index !== -1) {
        entry.resources.splice(index, 1)
        // si plus aucune resource n'utilise ce token manager, on le supprime
        if (entry.resources.length === 0 && removeTokenManagerIfNoResource) {
          this.#tokenManagers.delete(key)
        }
        break
      }
    }
  }

  /**
   * Est-ce que la clé de token manager existe déjà?
   * @param {import("./token-manager").tokenOptions | String} tokenOptions options de gestion du token ou token en clair (historique)
  * @returns {Boolean}
  */
  tokenSourceExists (tokenOptions) {
    const tokenKey = this.#getTokenManagerKey(tokenOptions)
    return this.#tokenManagers.has(tokenKey)
  }

  getTokenManager (tokenOptions) {
    const tokenKey = this.#getTokenManagerKey(tokenOptions)
    return this.#tokenManagers.has(tokenKey) ? this.#tokenManagers.get(tokenKey).tokenManager : null
  }

  /**
   * @param {import("./token-manager").tokenOptions | String} tokenOptions options de gestion du token ou token en clair (historique)
  * @returns {String}
  */
  #getTokenManagerKey (tokenOptions) {
    // génère une clé de token, si c'est une chaine de caractère, on la prend telle quelle
    // Sinon prend la propriété id
    // sinon calcule une clé en fonction de la chaine
    return typeof tokenOptions === 'string'
      ? tokenOptions
      : tokenOptions?.id
        ? tokenOptions.id
        : tokenOptions.type.toUpperCase() === 'FUNCTION'
          ? tokenOptions.toString()
          : JSON.stringify(tokenOptions)
  }
}