Commit 3d8dea90 authored by anuraghazra's avatar anuraghazra
Browse files

fix: github rate limiter with multiple PATs

parent 2efb399f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -18,7 +18,9 @@ module.exports = async (req, res) => {
  } = req.query;
  let stats;

  res.setHeader("Cache-Control", "public, max-age=300");
  res.setHeader("Content-Type", "image/svg+xml");

  try {
    stats = await fetchStats(username);
  } catch (err) {
+2 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@ module.exports = async (req, res) => {
  } = req.query;

  let repoData;
  
  res.setHeader("Cache-Control", "public, max-age=300");
  res.setHeader("Content-Type", "image/svg+xml");

  try {
+11 −6
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@ async function fetchRepo(username, reponame) {
    throw new Error("Invalid username or reponame");
  }

  const res = await request({
  const res = await request(
    {
      query: `
      fragment RepoInfo on Repository {
        name
@@ -37,7 +38,11 @@ async function fetchRepo(username, reponame) {
        login: username,
        repo: reponame,
      },
  });
    },
    {
      Authorization: `bearer ${process.env.PAT_1}`,
    }
  );

  const data = res.data.data;

+53 −15
Original line number Diff line number Diff line
@@ -2,25 +2,25 @@ const { request } = require("./utils");
const calculateRank = require("./calculateRank");
require("dotenv").config();

async function fetchStats(username) {
  if (!username) throw Error("Invalid username");

  const res = await request({
// creating a fetcher function to reduce duplication
const fetcher = (username, token) => {
  return request(
    {
      query: `
      query userInfo($login: String!) {
        user(login: $login) {
          name
          login
          repositoriesContributedTo(first: 100, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
            totalCount
          }
          contributionsCollection {
            totalCommitContributions
          }
          pullRequests(first: 100) {
          repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
            totalCount
          }
          issues(first: 100) {
          pullRequests(first: 1) {
            totalCount
          }
          issues(first: 1) {
            totalCount
          }
          followers {
@@ -38,7 +38,43 @@ async function fetchStats(username) {
      }
      `,
      variables: { login: username },
  });
    },
    {
      // set the token
      Authorization: `bearer ${token}`,
    }
  );
};

async function retryer(username, RETRIES) {
  try {
    console.log(`Trying PAT_${RETRIES + 1}`);

    // try to fetch with the first token since RETRIES is 0 index i'm adding +1
    let response = await fetcher(username, process.env[`PAT_${RETRIES + 1}`]);

    // if rate limit is hit increase the RETRIES and recursively call the retryer
    // with username, and current RETRIES
    if (
      response.data.errors &&
      response.data.errors[0].type === "RATE_LIMITED"
    ) {
      console.log(`PAT_${RETRIES} Failed`);
      RETRIES++;
      // directly return from the function
      return await retryer(username, RETRIES);
    }

    // finally return the response
    return response;
  } catch (err) {
    console.log(err);
  }
}

async function fetchStats(username) {
  let RETRIES = 0;
  if (!username) throw Error("Invalid username");

  const stats = {
    name: "",
@@ -47,12 +83,14 @@ async function fetchStats(username) {
    totalIssues: 0,
    totalStars: 0,
    contributedTo: 0,
    rank: "C",
    rank: { level: "C", score: 0 },
  };

  let res = await retryer(username, RETRIES);

  if (res.data.errors) {
    console.log(res.data.errors);
    throw Error("Could not fetch user");
    throw Error(res.data.errors[0].message || "Could not fetch user");
  }

  const user = res.data.data.user;
+9 −3
Original line number Diff line number Diff line
@@ -33,13 +33,13 @@ function isValidHexColor(hexColor) {
  ).test(hexColor);
}

function request(data) {
function request(data, headers) {
  return new Promise((resolve, reject) => {
    axios({
      url: "https://api.github.com/graphql",
      method: "post",
      headers: {
        Authorization: `bearer ${process.env.GITHUB_TOKEN}`,
        ...headers,
      },
      data,
    })
@@ -48,4 +48,10 @@ function request(data) {
  });
}

module.exports = { renderError, kFormatter, encodeHTML, isValidHexColor, request };
module.exports = {
  renderError,
  kFormatter,
  encodeHTML,
  isValidHexColor,
  request,
};
Loading