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
}
}