UNPKG

osu-api-extended

Version:

Advanced osu! api wrapper for v1 and v2, with extra stuff

184 lines 7.64 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.namespace = exports.download = exports.request = void 0; const auth = __importStar(require("../utility/auth")); const https_1 = __importDefault(require("https")); const fs_1 = __importDefault(require("fs")); const generateQueryString = (obj, trail = '') => { const params = []; const processValue = (key, value) => { if (Array.isArray(value)) { value.forEach((item) => { params.push(`${key}[]=${encodeURIComponent(item)}`); }); } else if (typeof value === 'object' && value !== null) { const newTrail = trail ? `${trail}.${key}` : key; params.push(generateQueryString(value, newTrail)); } else if (typeof value === 'number' && value > 0) { params.push(`${key}=${value}`); } else if (typeof value === 'string') { params.push(`${key}=${encodeURIComponent(value)}`); } }; for (const key in obj) { if (obj.hasOwnProperty(key)) { const value = obj[key]; if (value !== undefined) { processValue(key, value); } } } return params.join('&'); }; const TIMEOUT_MS = 60000; let amount_retry = 0; /** * Executes an HTTP request * @param {string} url The url * @returns {Promise<any>} The response */ const request = (url, { method = "GET", headers, data, params = {} } = {}) => { if (url.includes('https://osu.ppy.sh/api/') && !url.includes('https://osu.ppy.sh/api/v2')) { // @ts-ignore params.k = params.v1 || auth.cache_v1; } if (url.includes('https://osu.ppy.sh/api/v2')) headers = { // @ts-ignore Authorization: `Bearer ${params.v2 || auth.cache_v2}`, Accept: `application/json`, 'Content-Type': `application/json`, 'x-api-version': '20240130', }; // console.log({ url, method, headers, data, params: generateQueryString(params) }); // debug too return new Promise((resolve, reject) => { const req = https_1.default.request(url + (generateQueryString(params) ? `?${generateQueryString(params)}` : ''), { method, headers }, (response) => { const chunks = []; response.on('data', (chunk) => chunks.push(chunk)); response.on('end', async () => { const data = Buffer.concat(chunks).toString(); if (/^application\/json/.test(response.headers['content-type'])) { try { const parse = JSON.parse(data); if (parse.authentication === 'basic' && auth.cache_v2 && amount_retry < 3) { await auth.re_login(); amount_retry++; const again = await (0, exports.request)(url, { method, headers, data, params }); return resolve(again); } amount_retry = 0; return resolve(parse); } catch (err) { console.log(`JSON Parse on content of type ${response.headers['content-type']} failed.\nError: ${err}\nData: ${data}`); } } resolve(data); }); }).on('error', reject); req.setTimeout(TIMEOUT_MS, () => { req.destroy(); reject(new Error(`Request to ${url} time out after ${TIMEOUT_MS}ms`)); }); if (data) req.write(data); req.end(); }); }; exports.request = request; /** * Executes an HTTP request * @param {string} url The url * @param {string} dest The file destination * @returns {Promise<any>} The response */ const download = (url, dest, { headers = {}, data, params } = {}, callback) => { return new Promise((resolve, reject) => { if (url.includes('https://osu.ppy.sh/api/v2')) headers['Authorization'] = `Bearer ${auth.cache_v2}`; headers['accept'] = `application/octet-stream`; headers['content-Type'] = `application/octet-stream`; const req = https_1.default.request(url + (params ? '?' + generateQueryString(params) : ''), { method: 'GET', headers }, response => { const { location } = response.headers; if (location) { (0, exports.download)(location, dest, { headers, data, params }, callback) .then(resolve) .catch(reject); return; } if (response.statusCode === 404) { resolve({ error: 'file unavailable' }); return; } const file = fs_1.default.createWriteStream(dest, { encoding: 'utf8' }); file.on('error', err => { fs_1.default.unlinkSync(dest); reject(err); }); file.on('finish', () => { file.close(); resolve(dest); }); if (callback !== undefined) { const totalLength = parseInt(response.headers['content-length']); let progress = 0; let progressBar = 0; response.on('data', (chunk) => { progress += chunk.length; progressBar = 100 * (progress / totalLength); callback(progressBar); }); } response.pipe(file); }); req.setTimeout(TIMEOUT_MS, () => { req.destroy(); reject(new Error(`Request to ${url} time out after ${TIMEOUT_MS}ms`)); }); if (data) { req.write(data); } req.end(); }); }; exports.download = download; /** * Makes a namespace * @param {string} url The namespace url * @param {{ query?: string }} [params] Options ig * @returns {(params: string, { query: string }) => Promise<any>} The function that does the reqs */ const namespace = (url, { query } = {}) => { return (path, params) => (0, exports.request)(url + path, params); }; exports.namespace = namespace; //# sourceMappingURL=request.js.map