Source: services/token-manager.js

import Axios from 'axios'

/**
 * paramètre de type tokenOption
 * @typedef {Object} tokenOptions
 * @property {String} type Type de token (TOKEN, LOCALSTORAGE, URL, FUNCTION)
 * @property {String} [tokenKey = 'token'] Le nom de la clé à utiliser dans l'url pour envoyer le token (défaut 'token')
 * @property {Number} [refreshInterval] Intervalle de rafraichissement du token en ms (optionnel)
 * @property {String} [token] Le token (si type TOKEN)
 * @property {String} [path] Le path en localstorage (si type LOCALSTORAGE)
 * @property {String} [url] L'url à appeler pour récupérer le token (si type URL)
 * @property {String} [method] La méthode d'appel (GET, POST, PUT, DELETE) (si type URL) (défaut POST)
 * @property {Object} [data] Les données à envoyer (si type URL)
 * @property {Object} [headers] Les headers à envoyer (si type URL)
 * @property {String} [tokenName] Le nom de la propriété dans la réponse qui contient le token (si type URL)
 * @property {Object} [auth] Les informations d'authentification {username, password} (si type URL)
 * @property {Function} [tokenCallback] La fonction à appeler pour récupérer le token (si type FUNCTION)
 */

/**
 * Gestion d'un token
 */
export default class TokenManager {
  /**
   * @ type {tokenOptions | String}
   */
  #tokenOptions

  /**
   * @ type {String}
   */
  #tokenKey = 'token'

  /**
   * @ type {String | null}
   */
  #tokenValue

  #timoutManager = null

  get token () {
    return this.#tokenValue
  }

  /**
   * @param {tokenOptions | String} tokenOptions Options de gestion du token ou token en clair (historique)
   */
  constructor (tokenOptions) {
    this.#tokenOptions = tokenOptions
  }

  async init () {
    await this.#parseTokenOptions()
  }

  /** parsing des options de token */
  async #parseTokenOptions () {
    const tokenOptions = this.#tokenOptions
    // cas "historique", on a juste une chaine de caractère
    if (tokenOptions === null || typeof tokenOptions === 'string') {
      this.#tokenValue = tokenOptions
      return
    }

    if (typeof tokenOptions !== 'object' || !tokenOptions.type) {
      console.error('tokenOptions doit être une chaine de caractère ou un objet avec une propriété "type"')
      return
    }

    if (tokenOptions.tokenKey) {
      this.#tokenKey = tokenOptions.tokenKey
    }
    switch (tokenOptions.type.toUpperCase()) {
      // le token est dans une chaine de caractère
      case 'TOKEN':
        this.#tokenValue = tokenOptions.token
        break
      case 'LOCALSTORAGE':
        { // on essaye de lire le token en localstorage
          let tokenFromStorage = localStorage.getItem(tokenOptions.path)
          if (tokenFromStorage !== null && tokenFromStorage !== '') {
            try {
              tokenFromStorage = JSON.parse(tokenFromStorage)
              this.#tokenValue = tokenFromStorage.token
            } catch (ex) {
              console.error("erreur parsing du token, format {token:'1234'} attendu, recu : ", tokenOptions, ex)
            }
          }
        }
        break
      case 'URL':
        // on appelles une URL avec des options pour gérer le token
        {
          const { url, method = 'POST', data, headers, tokenName, auth } = tokenOptions
          const response = await Axios({
            url,
            auth,
            method,
            data,
            headers,
          })
          if (response.status === 200) {
            if (tokenName) {
              this.#tokenValue = response.data[tokenName]
            } else {
              this.#tokenValue = response.data
            }
          } else {
            console.error('erreur récupération du token', response)
          }
        }
        break
      case 'FUNCTION':
        // on appelle une fonction pour récupérer le token
        this.#tokenValue = await tokenOptions.tokenCallback()
        break
    }

    // on a défini qu'il fallait rafraichir le token
    if (this.#tokenOptions.refreshInterval) {
      this.#timoutManager = setTimeout(this.#parseTokenOptions.bind(this, tokenOptions), this.#tokenOptions.refreshInterval)
    }
  }

  destroy () {
    if (this.#timoutManager) {
      clearTimeout(this.#timoutManager)
      this.#timoutManager = null
    }
  }

  pause () {
    if (this.#timoutManager) {
      clearTimeout(this.#timoutManager)
      this.#timoutManager = null
    }
  }

  async restart () {
    this.pause()
    await this.init()
  }

  /**
   * Parse une url pour y ajouter le token
   * @param {String} url
   * @returns {String} url avec token
   */
  addTokenToUrl (url) {
    if (this.token) {
      url += url.indexOf('?') === -1 ? `?${this.#tokenKey}=${this.#tokenValue}` : `&${this.#tokenKey}=${this.#tokenValue}`
    }
    return url
  }
}