0.6.27 • Published 5 months ago

@synzen/discord-rest v0.6.27

Weekly downloads
58
License
MIT
Repository
github
Last release
5 months ago

Discord-REST

A distributed Discord rate limit handler that uses isomorphic-fetch's interface for easy use.

Requesta are enqueued into RabbitMQ using a producer, and is consumed by a consumer.

By default, outgoing requests are throttled at a maximum of 30/second (lower than the the maximum allowed by Discord, which is 50, to give some buffer for other requests).

Table of Contents

Install

npm i @synzen/discord-rest

Usage

  1. Set up a RESTConsumer to get ready to consume incoming requests.

    import { RESTConsumer } from "@synzen/discord-rest";
    
    const consumer = new RESTConsumer(rabbitmqUri, {
      authHeader: `Bot ${botToken}`,
      clientId: 'Bot client id'
    });
    
    consumer.initialize()
    .then(() => console.log('Initialized'))
    .catch(console.error)
    
    // You can use the consumer to also listen to important events. See #handle-invalid-requests section
  2. Set up a RESTProducer to send out API requests. Only requests that expect Content-Type: application/json is currently supported for simplicity and for it to be serializable to be stored within Redis.

    import { RESTConsumer } from "@synzen/discord-rest";
    
    const producer = new RESTProducer(rabbitmqUri, {
    clientId: 'Bot client id'
    });
    
    producer
      .enqueue(
        discordEndpoint,
        {
          // node-fetch options.
          method: "POST",
          body: JSON.stringify(payload),
        },
        {
          // Any meta info you'd like to attach to this request
          meta: 1,
        }
      )
      .then((response) => {
        // Status code (200, 400, etc.)
        console.log(response.status);
        // JSON response
        console.log(response.body);
      })
      .catch(console.error);

    If you execute multiple requests asynchronously, for example:

    for (let i = 0; i < 3; ++i) {
      producer
        .enqueue("https://discord.com/api/channels/channelID/messages", {
          method: "POST",
          body: JSON.stringify({
            content: i,
          }),
        })
        .then(() => console.log(i))
        .catch(console.error);
    }
    1
    2
    3

    You will notice that they are executed in order since they are all within the same rate limit bucket.

Handle Invalid Requests

If you encounter too many invalid requests within a certain time frame, Discord will temporarily block your IP as noted in https://discord.com/developers/docs/topics/rate-limits#invalid-request-limit. An invalid request (as it is currently defined at the time of this writing), is a response of 429, 401, or 403. The hard limit for Discord is 10,000 invalid requests within 10 minutes. You can listen for invalid requests like so:

const consumer = new RESTConsumer();

// Listen for API responses with status codes 429, 401 and 403
consumer.handler.on("invalidRequest", (apiRequest, countSoFar) => {
  console.error(
    `Invalid request for ${apiRequest.toString()} (${countSoFar} total within 10 minutes)`
  );
});

This library will delay and queue up all further requests for 10 minutes after it encounters 5,000 invalid requests within 10 minutes. You can listen to this event.

consumer.handler.on("invalidRequestsThreshold", (threshold) => {
  console.error(
    `Number of invalid requests exceeded threshold (${threshold}), delaying all tasks by 10 minutes`
  );
});

If you'd like to specifically listen for rate limit hits, you can use the following events.

// Listen for bucket rate limit encounters
consumer.handler.on("rateLimit", (apiRequest, blockedDurationMs) => {
  console.error(
    `Bucket rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`
  );
});

// Listen for global rate limit encounters
consumer.handler.on("globalRateLimit", (apiRequest, blockedDurationMs) => {
  console.error(
    `Global rate limit hit for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`
  );
});

// Listen for cloudflare IP bans
consumer.handler.on("cloudflareLimit", (apiRequest, blockedDurationMs) => {
  console.error(
    `Cloudflare IP ban detected for ${apiRequest.toString()} (blocked for ${blockedDurationMs}ms)`
  );
});

Debugging

Set the environment variable DEBUG to discordrest:*.

DEBUG=discordrest:*

or on Windows:

set DEBUG=discordrest:*

You will see output like below.

discordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#5) +0ms
discordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#6) +0ms
discordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#7) +1ms
discordrest:bucket:0123--4567- Enqueuing request https://discord.com/api/channels/4567/messages (#8) +0ms
discordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#5) +1ms
discordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#5) +79ms
discordrest:bucket:0123--4567- Blocking for 1000ms after non-429 response for https://discord.com/api/channels/4567/messages (#5) +2ms
discordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#5) +1ms
discordrest:bucket:0123--4567- Delaying execution until Sun Aug 30 2020 12:18:35 GMT-0400 (Eastern Daylight Time) for https://discord.com/api/channels/4567/messages (#6) +1ms
discordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#6) +1s
discordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#6) +106ms
discordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#6) +3ms
discordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#7) +1ms
discordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#7) +88ms
discordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#7) +0ms
discordrest:bucket:0123--4567- Executing https://discord.com/api/channels/4567/messages (#8) +1ms
discordrest:bucket:0123--4567- Non-429 response for https://discord.com/api/channels/4567/messages (#8) +88ms
discordrest:bucket:0123--4567- Finished entire queue +1ms
discordrest:bucket:0123--4567- Finished https://discord.com/api/channels/4567/messages (#8) +1ms
0.7.0-beta.10

5 months ago

0.7.0-beta.11

5 months ago

0.7.0-beta.8

9 months ago

0.7.0-beta.9

9 months ago

0.7.0-beta.5

1 year ago

0.7.0-beta.6

1 year ago

0.7.0-beta.7

1 year ago

0.7.0-beta.3

1 year ago

0.7.0-beta.4

1 year ago

0.6.27-beta.0

2 years ago

0.6.26-beta.48

2 years ago

0.7.0-beta.0

2 years ago

0.7.0-beta.1

2 years ago

0.7.0-beta.2

2 years ago

0.6.26-beta.47

2 years ago

0.6.26-beta.45

2 years ago

0.6.26-beta.46

2 years ago

0.6.27

2 years ago

0.6.26-beta.40

2 years ago

0.6.26-beta.43

2 years ago

0.6.26-beta.44

2 years ago

0.6.26-beta.41

2 years ago

0.6.26-beta.42

2 years ago

0.6.26-beta.36

2 years ago

0.6.26-beta.37

2 years ago

0.6.26-beta.34

2 years ago

0.6.26-beta.35

2 years ago

0.6.26-beta.32

2 years ago

0.6.26-beta.33

2 years ago

0.6.26-beta.30

2 years ago

0.6.26-beta.31

2 years ago

0.6.26-beta.38

2 years ago

0.6.26-beta.39

2 years ago

0.6.26-beta.25

2 years ago

0.6.26-beta.26

2 years ago

0.6.26-beta.23

2 years ago

0.6.26-beta.24

2 years ago

0.6.26-beta.21

2 years ago

0.6.26-beta.22

2 years ago

0.6.26-beta.20

2 years ago

0.6.26-beta.8

2 years ago

0.6.26-beta.7

2 years ago

0.6.26-beta.9

2 years ago

0.6.26-beta.29

2 years ago

0.6.26-beta.4

2 years ago

0.6.26-beta.3

2 years ago

0.6.26-beta.27

2 years ago

0.6.26-beta.6

2 years ago

0.6.26-beta.28

2 years ago

0.6.26-beta.5

2 years ago

0.6.26-beta.0

2 years ago

0.6.26-beta.2

2 years ago

0.6.26-beta.1

2 years ago

0.6.26-beta.14

2 years ago

0.6.26-beta.15

2 years ago

0.6.26-beta.12

2 years ago

0.6.26-beta.13

2 years ago

0.6.26-beta.10

2 years ago

0.6.26-beta.11

2 years ago

0.6.26-beta.18

2 years ago

0.6.26-beta.19

2 years ago

0.6.26-beta.16

2 years ago

0.6.26-beta.17

2 years ago

0.6.21

2 years ago

0.6.23

2 years ago

0.6.22

2 years ago

0.6.25

2 years ago

0.6.24

2 years ago

0.6.26

2 years ago

0.6.19

3 years ago

0.6.12

3 years ago

0.6.18

3 years ago

0.6.17

3 years ago

0.6.14

3 years ago

0.6.13

3 years ago

0.6.16

3 years ago

0.6.15

3 years ago

0.6.7

3 years ago

0.6.6

3 years ago

0.6.9

3 years ago

0.6.8

3 years ago

0.6.10

3 years ago

0.6.11

3 years ago

0.6.3

3 years ago

0.6.2

3 years ago

0.6.5

3 years ago

0.6.4

3 years ago

0.6.1

3 years ago

0.6.0

3 years ago

0.5.2

3 years ago

0.5.0

3 years ago

0.5.1

3 years ago

0.3.0

4 years ago

0.3.2

4 years ago

0.4.0

4 years ago

0.3.1

4 years ago

0.3.3

4 years ago

0.2.1

4 years ago

0.1.0

4 years ago

0.2.0

4 years ago

0.1.1

4 years ago

0.0.8

4 years ago

0.0.7

4 years ago

0.0.6

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.3

4 years ago

0.0.2

4 years ago

0.0.1

4 years ago