magmastream
Version:
A user-friendly Lavalink client designed for NodeJS.
204 lines (203 loc) • 9.37 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Rest = void 0;
const undici_1 = require("undici");
const Enums_1 = require("./Enums");
const Utils_1 = require("./Utils");
const MagmastreamError_1 = require("./MagmastreamError");
/** Handles the requests sent to the Lavalink REST API. */
class Rest {
/** The Node that this Rest instance is connected to. */
node;
/** The password for the Node. */
password;
/** The URL of the Node. */
url;
/** The Manager instance. */
manager;
/** Whether the node is a NodeLink. */
isNodeLink = false;
constructor(node, manager) {
this.node = node;
this.url = `http${node.options.useSSL ? "s" : ""}://${node.options.host}:${node.options.port}`;
this.password = node.options.password;
this.manager = manager;
this.isNodeLink = node.isNodeLink;
}
/**
* Gets the session ID.
* @returns {string} Returns the session ID.
*/
get sessionId() {
return this.node.sessionId;
}
/**
* Sets the session ID.
* This method is used to set the session ID after a resume operation is done.
* @param {string} sessionId The session ID to set.
* @returns {string} Returns the set session ID.
*/
setSessionId(sessionId) {
this.node.sessionId = sessionId;
return this.node.sessionId;
}
/**
* Retrieves the player that is currently running on the node.
* @param {string} guildId The guild ID of the player to retrieve.
* @returns {Promise<LavaPlayer>} Returns the player.
*/
async getPlayer(guildId) {
if (!this.sessionId) {
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping getPlayer for ${guildId} - no session ID on node ${this.node.options.identifier}`);
return null;
}
const result = await this.get(`/v4/sessions/${this.sessionId}/players/${guildId}`);
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Getting player on node: ${this.node.options.identifier} : ${Utils_1.JSONUtils.safe(result, 2)}`);
return result;
}
/**
* Sends a PATCH request to update player related data.
* @param {RestPlayOptions} options The options to update the player with.
* @returns {Promise<LavaPlayer>} Returns the updated player.
*/
async updatePlayer(options) {
if (!this.sessionId) {
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping updatePlayer for guildId: ${options.guildId} - no session ID on node ${this.node.options.identifier}`);
return null;
}
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating player: ${options.guildId}: ${Utils_1.JSONUtils.safe(options, 2)}`);
return await this.patch(`/v4/sessions/${this.sessionId}/players/${options.guildId}?noReplace=${options.noReplace ?? false}`, options.data);
}
/**
* Sends a DELETE request to the server to destroy the player.
* @param {string} guildId The guild ID of the player to destroy.
* @returns {Promise<void>} Returns void (204 No Content).
*/
async destroyPlayer(guildId) {
if (!this.sessionId) {
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping destroyPlayer for guildId: ${guildId} - no session ID on node ${this.node.options.identifier}`);
return;
}
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Destroying player: ${guildId}`);
return await this.delete(`/v4/sessions/${this.sessionId}/players/${guildId}`);
}
/**
* Updates the session status for resuming.
* @param {boolean} resuming - Indicates whether the session should be set to resuming.
* @param {number} timeout - The timeout duration for the session resume.
* @returns {Promise<LavalinkSession>} The updated session.
*/
async updateSession(resuming, timeout) {
if (!this.sessionId) {
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Skipping updateSession for resuming: ${resuming} timeout: ${timeout} - no session ID on node ${this.node.options.identifier}`);
return null;
}
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] Updating session: ${this.sessionId}`);
return await this.patch(`/v4/sessions/${this.sessionId}`, { resuming, timeout });
}
/**
* Sends a request to the specified endpoint and returns the response data.
* @param {string} method The HTTP method to use for the request.
* @param {string} endpoint The endpoint to send the request to.
* @param {unknown} [body] The data to send in the request body.
* @returns {Promise<unknown>} The response data of the request.
*/
async request(method, endpoint, body) {
this.manager.emit(Enums_1.ManagerEventTypes.Debug, `[REST] ${method} request to ${endpoint} with body: ${Utils_1.JSONUtils.safe(body, 2)}`);
let response = null;
try {
response = await (0, undici_1.fetch)(this.url + endpoint, {
method,
headers: {
"Content-Type": "application/json",
Authorization: this.password,
},
body: body !== undefined ? JSON.stringify(body) : undefined,
signal: AbortSignal.timeout(this.node.options.apiRequestTimeoutMs),
});
}
catch (e) {
const isTimeout = e instanceof Error && (e.name === "AbortError" || e.name === "TimeoutError");
const message = e instanceof Error ? e.message : "Unknown error";
const error = new MagmastreamError_1.MagmaStreamError({
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
message: `${isTimeout ? "Timeout" : "Network error"} on ${method} ${endpoint}: ${message}`,
});
this.manager.emit(Enums_1.ManagerEventTypes.NodeError, this.node, error);
return null;
}
const { status } = response;
const data = status !== 204 ? await response.json() : null;
if (status >= 200 && status < 300) {
return data;
}
if (status === 404) {
if (data?.message === "Guild not found") {
return [];
}
if (data?.message === "Session not found") {
this.manager.emit(Enums_1.ManagerEventTypes.NodeError, this.node, new MagmastreamError_1.MagmaStreamError({ code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED, message: "Session not found" }));
return [];
}
}
const message = typeof data === "string"
? data
: typeof data === "object" && data !== null && "message" in data && typeof data.message === "string"
? data.message
: Utils_1.JSONUtils.safe(data, 2);
if (status === 401) {
throw new MagmastreamError_1.MagmaStreamError({
code: Enums_1.MagmaStreamErrorCode.REST_UNAUTHORIZED,
message: `Unauthorized access to node ${this.node.options.identifier}`,
});
}
throw new MagmastreamError_1.MagmaStreamError({
code: Enums_1.MagmaStreamErrorCode.REST_REQUEST_FAILED,
message: `Request to node ${this.node.options.identifier} failed (${status}): ${message}`,
});
}
/**
* Sends a GET request to the specified endpoint and returns the response data.
* @param {string} endpoint The endpoint to send the GET request to.
* @returns {Promise<T>} The response data of the GET request.
*/
async get(endpoint) {
return (await this.request("GET", endpoint));
}
/**
* Sends a PATCH request to the specified endpoint and returns the response data.
* @param {string} endpoint The endpoint to send the PATCH request to.
* @param {unknown} body The data to send in the request body.
* @returns {Promise<T>} The response data of the PATCH request.
*/
async patch(endpoint, body) {
return (await this.request("PATCH", endpoint, body));
}
/**
* Sends a POST request to the specified endpoint and returns the response data.
* @param {string} endpoint The endpoint to send the POST request to.
* @param {unknown} body The data to send in the request body.
* @returns {Promise<T>} The response data of the POST request.
*/
async post(endpoint, body) {
return (await this.request("POST", endpoint, body));
}
/**
* Sends a PUT request to the specified endpoint and returns the response data.
* @param {string} endpoint The endpoint to send the PUT request to.
* @param {unknown} body The data to send in the request body.
* @returns {Promise<T>} The response data of the PUT request.
*/
async put(endpoint, body) {
return (await this.request("PUT", endpoint, body));
}
/**
* Sends a DELETE request to the specified endpoint.
* @param {string} endpoint - The endpoint to send the DELETE request to.
* @returns {Promise<void>} Void.
*/
async delete(endpoint) {
await this.request("DELETE", endpoint);
}
}
exports.Rest = Rest;