| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 | import axios from "axios";import CoreClass from "../core";import { MUSARE_VERSION } from "..";class RateLimitter {	/**	 * Constructor	 * @param {number} timeBetween - The time between each allowed MusicBrainz request	 */	constructor(timeBetween) {		this.dateStarted = Date.now();		this.timeBetween = timeBetween;	}	/**	 * Returns a promise that resolves whenever the ratelimit of a MusicBrainz request is done	 * @returns {Promise} - promise that gets resolved when the rate limit allows it	 */	continue() {		return new Promise(resolve => {			if (Date.now() - this.dateStarted >= this.timeBetween) resolve();			else setTimeout(resolve, this.dateStarted + this.timeBetween - Date.now());		});	}	/**	 * Restart the rate limit timer	 */	restart() {		this.dateStarted = Date.now();	}}let MusicBrainzModule;let DBModule;class _MusicBrainzModule extends CoreClass {	// eslint-disable-next-line require-jsdoc	constructor() {		super("musicbrainz", {			concurrency: 10		});		MusicBrainzModule = this;	}	/**	 * Initialises the MusicBrainz module	 * @returns {Promise} - returns promise (reject, resolve)	 */	async initialize() {		DBModule = this.moduleManager.modules.db;		this.genericApiRequestModel = this.GenericApiRequestModel = await DBModule.runJob("GET_MODEL", {			modelName: "genericApiRequest"		});		this.rateLimiter = new RateLimitter(1100);		this.requestTimeout = 5000;		this.axios = axios.create();	}	/**	 * Perform MusicBrainz API call	 * @param {object} payload - object that contains the payload	 * @param {string} payload.url - request url	 * @param {object} payload.params - request parameters	 * @returns {Promise} - returns promise (reject, resolve)	 */	async API_CALL(payload) {		const { url, params } = payload;		let genericApiRequest = await MusicBrainzModule.GenericApiRequestModel.findOne({			url,			params		});		if (genericApiRequest) {			if (genericApiRequest._doc.responseData.error) throw new Error(genericApiRequest._doc.responseData.error);			return genericApiRequest._doc.responseData;		}		await MusicBrainzModule.rateLimiter.continue();		MusicBrainzModule.rateLimiter.restart();		const responseData = await new Promise((resolve, reject) => {			MusicBrainzModule.axios				.get(url, {					params,					headers: {						"User-Agent": `Musare/${MUSARE_VERSION} ( https://github.com/Musare/Musare )` // TODO set this in accordance to https://musicbrainz.org/doc/MusicBrainz_API/Rate_Limiting					},					timeout: MusicBrainzModule.requestTimeout				})				.then(({ data: responseData }) => {					resolve(responseData);				})				.catch(err => {					if (err.response.status === 404) {						resolve(err.response.data);					} else reject(err);				});		});		if (responseData.error && responseData.error !== "Not Found") throw new Error(responseData.error);		genericApiRequest = new MusicBrainzModule.GenericApiRequestModel({			url,			params,			responseData,			date: Date.now()		});		genericApiRequest.save();		if (responseData.error) throw new Error(responseData.error);		return responseData;	}}export default new _MusicBrainzModule();
 |