async function processQueue(
  id,
) {
  const queue = rest.pathQueues.get(id);
  if (!queue) return;
  while (queue.length) {
    rest.eventHandlers.debug?.(
      "loop",
      "Running while loop in processQueue function.",
    );
    // IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN
    if (rest.globallyRateLimited) {
      setTimeout(async () => {
        eventHandlers.debug?.(
          "loop",
          `Running setTimeout in processQueue function.`,
        );
        await processQueue(id);
      }, 1000);
      break;
    }
    // SELECT THE FIRST ITEM FROM THIS QUEUE
    const [queuedRequest] = queue;
    // IF THIS DOESNT HAVE ANY ITEMS JUST CANCEL, THE CLEANER WILL REMOVE IT.
    if (!queuedRequest) return;
    const basicURL = rest.simplifyUrl(
      queuedRequest.request.url,
      queuedRequest.request.method.toUpperCase(),
    );
    // IF THIS URL IS STILL RATE LIMITED, TRY AGAIN
    const urlResetIn = rest.checkRateLimits(basicURL);
    if (urlResetIn) {
      // PAUSE FOR THIS SPECIFC REQUEST
      await delay(urlResetIn);
      continue;
    }
    // IF A BUCKET EXISTS, CHECK THE BUCKET'S RATE LIMITS
    const bucketResetIn = queuedRequest.payload.bucketId
      ? rest.checkRateLimits(queuedRequest.payload.bucketId)
      : false;
    // THIS BUCKET IS STILL RATELIMITED, RE-ADD TO QUEUE
    if (bucketResetIn) continue;
    // EXECUTE THE REQUEST
    // IF THIS IS A GET REQUEST, CHANGE THE BODY TO QUERY PARAMETERS
    const query = queuedRequest.request.method.toUpperCase() === "GET" &&
        queuedRequest.payload.body
      ? Object.entries(queuedRequest.payload.body).map(([key, value]) =>
        `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
      ).join("&")
      : "";
    const urlToUse =
      queuedRequest.request.method.toUpperCase() === "GET" && query
        ? `${queuedRequest.request.url}?${query}`
        : queuedRequest.request.url;
    // CUSTOM HANDLER FOR USER TO LOG OR WHATEVER WHENEVER A FETCH IS MADE
    rest.eventHandlers.fetching(queuedRequest.payload);
    try {
      const response = await fetch(
        urlToUse,
        rest.createRequestBody(queuedRequest),
      );
      rest.eventHandlers.fetched(queuedRequest.payload);
      const bucketIdFromHeaders = rest.processRequestHeaders(
        basicURL,
        response.headers,
      );
      // SET THE BUCKET Id IF IT WAS PRESENT
      if (bucketIdFromHeaders) {
        queuedRequest.payload.bucketId = bucketIdFromHeaders;
      }
      if (response.status < 200 || response.status >= 400) {
        rest.eventHandlers.error("httpError", queuedRequest.payload, response);
        let error = "REQUEST_UNKNOWN_ERROR";
        switch (response.status) {
          case DiscordHTTPResponseCodes.BadRequest:
            error =
              "The request was improperly formatted, or the server couldn't understand it.";
            break;
          case DiscordHTTPResponseCodes.Unauthorized:
            error = "The Authorization header was missing or invalid.";
            break;
          case DiscordHTTPResponseCodes.Forbidden:
            error =
              "The Authorization token you passed did not have permission to the resource.";
            break;
          case DiscordHTTPResponseCodes.NotFound:
            error = "The resource at the location specified doesn't exist.";
            break;
          case DiscordHTTPResponseCodes.MethodNotAllowed:
            error =
              "The HTTP method used is not valid for the location specified.";
            break;
          case DiscordHTTPResponseCodes.GatewayUnavailable:
            error =
              "There was not a gateway available to process your request. Wait a bit and retry.";
            break;
        }
        queuedRequest.request.reject?.(
          new Error(`[${response.status}] ${error}`),
        );
        // If Rate limited should not remove from queue
        if (response.status !== 429) queue.shift();
        continue;
      }
      // SOMETIMES DISCORD RETURNS AN EMPTY 204 RESPONSE THAT CAN'T BE MADE TO JSON
      if (response.status === 204) {
        rest.eventHandlers.fetchSuccess(queuedRequest.payload);
        // REMOVE FROM QUEUE
        queue.shift();
        queuedRequest.request.respond({
          status: 204,
        });
      } else {
        // CONVERT THE RESPONSE TO JSON
        const json = await response.json();
        // IF THE RESPONSE WAS RATE LIMITED, HANDLE ACCORDINGLY
        if (
          json.retry_after || json.message === "You are being rate limited."
        ) {
          // IF IT HAS MAXED RETRIES SOMETHING SERIOUSLY WRONG. CANCEL OUT.
          if (queuedRequest.payload.retryCount >= rest.maxRetryCount) {
            rest.eventHandlers.retriesMaxed(queuedRequest.payload);
            queuedRequest.request.respond({
              status: 200,
              body: JSON.stringify({
                error:
                  "The request was rate limited and it maxed out the retries limit.",
              }),
            });
            // REMOVE ITEM FROM QUEUE TO PREVENT RETRY
            queue.shift();
            continue;
          }
          continue;
        }
        rest.eventHandlers.fetchSuccess(queuedRequest.payload);
        // REMOVE FROM QUEUE
        queue.shift();
        queuedRequest.request.respond({
          status: 200,
          body: JSON.stringify(json),
        });
      }
    } catch (error) {
      // SOMETHING WENT WRONG, LOG AND RESPOND WITH ERROR
      rest.eventHandlers.fetchFailed(queuedRequest.payload, error);
      queuedRequest.request.reject?.(error);
      // REMOVE FROM QUEUE
      queue.shift();
    }
  }
  // ONCE QUEUE IS DONE, WE CAN TRY CLEANING UP
  rest.cleanupQueues();
}
/** Processes the queue by looping over each path separately until the queues are empty. */
Processes the queue by looping over each path separately until the queues are empty.
Processes the queue by looping over each path separately until the queues are empty .
async function processQueue(
  id,
) {
  const queue = rest.pathQueues.get(id);
  if (!queue) return;
  while (queue.length) {
    rest.eventHandlers.debug?.(
      "loop",
      "Running while loop in processQueue function.",
    );
    if (rest.globallyRateLimited) {
      setTimeout(async () => {
        eventHandlers.debug?.(
          "loop",
          `Running setTimeout in processQueue function.`,
        );
        await processQueue(id);
      }, 1000);
      break;
    }
    const [queuedRequest] = queue;
    if (!queuedRequest) return;
    const basicURL = rest.simplifyUrl(
      queuedRequest.request.url,
      queuedRequest.request.method.toUpperCase(),
    );
    const urlResetIn = rest.checkRateLimits(basicURL);
    if (urlResetIn) {
      await delay(urlResetIn);
      continue;
    }
    const bucketResetIn = queuedRequest.payload.bucketId
      ? rest.checkRateLimits(queuedRequest.payload.bucketId)
      : false;
    if (bucketResetIn) continue;
    const query = queuedRequest.request.method.toUpperCase() === "GET" &&
        queuedRequest.payload.body
      ? Object.entries(queuedRequest.payload.body).map(([key, value]) =>
        `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
      ).join("&")
      : "";
    const urlToUse =
      queuedRequest.request.method.toUpperCase() === "GET" && query
        ? `${queuedRequest.request.url}?${query}`
        : queuedRequest.request.url;
    rest.eventHandlers.fetching(queuedRequest.payload);
    try {
      const response = await fetch(
        urlToUse,
        rest.createRequestBody(queuedRequest),
      );
      rest.eventHandlers.fetched(queuedRequest.payload);
      const bucketIdFromHeaders = rest.processRequestHeaders(
        basicURL,
        response.headers,
      );
      if (bucketIdFromHeaders) {
        queuedRequest.payload.bucketId = bucketIdFromHeaders;
      }
      if (response.status < 200 || response.status >= 400) {
        rest.eventHandlers.error("httpError", queuedRequest.payload, response);
        let error = "REQUEST_UNKNOWN_ERROR";
        switch (response.status) {
          case DiscordHTTPResponseCodes.BadRequest:
            error =
              "The request was improperly formatted, or the server couldn't understand it.";
            break;
          case DiscordHTTPResponseCodes.Unauthorized:
            error = "The Authorization header was missing or invalid.";
            break;
          case DiscordHTTPResponseCodes.Forbidden:
            error =
              "The Authorization token you passed did not have permission to the resource.";
            break;
          case DiscordHTTPResponseCodes.NotFound:
            error = "The resource at the location specified doesn't exist.";
            break;
          case DiscordHTTPResponseCodes.MethodNotAllowed:
            error =
              "The HTTP method used is not valid for the location specified.";
            break;
          case DiscordHTTPResponseCodes.GatewayUnavailable:
            error =
              "There was not a gateway available to process your request. Wait a bit and retry.";
            break;
        }
        queuedRequest.request.reject?.(
          new Error(`[${response.status}] ${error}`),
        );
        if (response.status !== 429) queue.shift();
        continue;
      }
      if (response.status === 204) {
        rest.eventHandlers.fetchSuccess(queuedRequest.payload);
        queue.shift();
        queuedRequest.request.respond({
          status: 204,
        });
      } else {
        const json = await response.json();
        if (
          json.retry_after || json.message === "You are being rate limited."
        ) {
          if (queuedRequest.payload.retryCount >= rest.maxRetryCount) {
            rest.eventHandlers.retriesMaxed(queuedRequest.payload);
            queuedRequest.request.respond({
              status: 200,
              body: JSON.stringify({
                error:
                  "The request was rate limited and it maxed out the retries limit.",
              }),
            });
            queue.shift();
            continue;
          }
          continue;
        }
        rest.eventHandlers.fetchSuccess(queuedRequest.payload);
        queue.shift();
        queuedRequest.request.respond({
          status: 200,
          body: JSON.stringify(json),
        });
      }
    } catch (error) {
      rest.eventHandlers.fetchFailed(queuedRequest.payload, error);
      queuedRequest.request.reject?.(error);
      queue.shift();
    }
  }
  rest.cleanupQueues();
}
async function processQueue ( id , ) { const queue = rest . pathQueues . get ( id ) ; if ( ! queue ) return ; while ( queue . length ) { rest . eventHandlers . debug ?. ( "loop" , "Running while loop in processQueue function." , ) ; if ( rest . globallyRateLimited ) { setTimeout ( async ( ) => { eventHandlers . debug ?. ( "loop" , ` ` , ) ; await processQueue ( id ) ; } , 1000 ) ; break ; } const [ queuedRequest ] = queue ; if ( ! queuedRequest ) return ; const basicURL = rest . simplifyUrl ( queuedRequest . request . url , queuedRequest . request . method . toUpperCase ( ) , ) ; const urlResetIn = rest . checkRateLimits ( basicURL ) ; if ( urlResetIn ) { await delay ( urlResetIn ) ; continue ; } const bucketResetIn = queuedRequest . payload . bucketId ? rest . checkRateLimits ( queuedRequest . payload . bucketId ) : false ; if ( bucketResetIn ) continue ; const query = queuedRequest . request . method . toUpperCase ( ) === "GET" && queuedRequest . payload . body ? Object . entries ( queuedRequest . payload . body ) . map ( ( [ key , value ] ) => ` ${ encodeURIComponent ( key ) } ${ encodeURIComponent ( value ) } ` ) . join ( "&" ) : "" ; const urlToUse = queuedRequest . request . method . toUpperCase ( ) === "GET" && query ? ` ${ queuedRequest . request . url } ${ query } ` : queuedRequest . request . url ; rest . eventHandlers . fetching ( queuedRequest . payload ) ; try { const response = await fetch ( urlToUse , rest . createRequestBody ( queuedRequest ) , ) ; rest . eventHandlers . fetched ( queuedRequest . payload ) ; const bucketIdFromHeaders = rest . processRequestHeaders ( basicURL , response . headers , ) ; if ( bucketIdFromHeaders ) { queuedRequest . payload . bucketId = bucketIdFromHeaders ; } if ( response . status < 200 || response . status >= 400 ) { rest . eventHandlers . error ( "httpError" , queuedRequest . payload , response ) ; let error = "REQUEST_UNKNOWN_ERROR" ; switch ( response . status ) { case DiscordHTTPResponseCodes . BadRequest : error = "The request was improperly formatted, or the server couldn't understand it." ; break ; case DiscordHTTPResponseCodes . Unauthorized : error = "The Authorization header was missing or invalid." ; break ; case DiscordHTTPResponseCodes . Forbidden : error = "The Authorization token you passed did not have permission to the resource." ; break ; case DiscordHTTPResponseCodes . NotFound : error = "The resource at the location specified doesn't exist." ; break ; case DiscordHTTPResponseCodes . MethodNotAllowed : error = "The HTTP method used is not valid for the location specified." ; break ; case DiscordHTTPResponseCodes . GatewayUnavailable : error = "There was not a gateway available to process your request. Wait a bit and retry." ; break ; } queuedRequest . request . reject ?. ( new Error ( ` ${ response . status } ${ error } ` ) , ) ; if ( response . status !== 429 ) queue . shift ( ) ; continue ; } if ( response . status === 204 ) { rest . eventHandlers . fetchSuccess ( queuedRequest . payload ) ; queue . shift ( ) ; queuedRequest . request . respond ( { status : 204 , } ) ; } else { const json = await response . json ( ) ; if ( json . retry_after || json . message === "You are being rate limited." ) { if ( queuedRequest . payload . retryCount >= rest . maxRetryCount ) { rest . eventHandlers . retriesMaxed ( queuedRequest . payload ) ; queuedRequest . request . respond ( { status : 200 , body : JSON . stringify ( { error : "The request was rate limited and it maxed out the retries limit." , } ) , } ) ; queue . shift ( ) ; continue ; } continue ; } rest . eventHandlers . fetchSuccess ( queuedRequest . payload ) ; queue . shift ( ) ; queuedRequest . request . respond ( { status : 200 , body : JSON . stringify ( json ) , } ) ; } } catch ( error ) { rest . eventHandlers . fetchFailed ( queuedRequest . payload , error ) ; queuedRequest . request . reject ?. ( error ) ; queue . shift ( ) ; } } rest . cleanupQueues ( ) ; }
Processes the queue by looping over each path separately until the queues are empty.
Processes the queue by looping over each path separately until the queues are empty .
// IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN // SELECT THE FIRST ITEM FROM THIS QUEUE // IF THIS DOESNT HAVE ANY ITEMS JUST CANCEL, THE CLEANER WILL REMOVE IT. // IF THIS URL IS STILL RATE LIMITED, TRY AGAIN // PAUSE FOR THIS SPECIFC REQUEST // IF A BUCKET EXISTS, CHECK THE BUCKET'S RATE LIMITS // THIS BUCKET IS STILL RATELIMITED, RE-ADD TO QUEUE // EXECUTE THE REQUEST // IF THIS IS A GET REQUEST, CHANGE THE BODY TO QUERY PARAMETERS // CUSTOM HANDLER FOR USER TO LOG OR WHATEVER WHENEVER A FETCH IS MADE // SET THE BUCKET Id IF IT WAS PRESENT // If Rate limited should not remove from queue // SOMETIMES DISCORD RETURNS AN EMPTY 204 RESPONSE THAT CAN'T BE MADE TO JSON // REMOVE FROM QUEUE // CONVERT THE RESPONSE TO JSON // IF THE RESPONSE WAS RATE LIMITED, HANDLE ACCORDINGLY // IF IT HAS MAXED RETRIES SOMETHING SERIOUSLY WRONG. CANCEL OUT. // REMOVE ITEM FROM QUEUE TO PREVENT RETRY // REMOVE FROM QUEUE // SOMETHING WENT WRONG, LOG AND RESPOND WITH ERROR // REMOVE FROM QUEUE // ONCE QUEUE IS DONE, WE CAN TRY CLEANING UP