mirror of
https://github.com/Aviortheking/codestats-readme.git
synced 2025-04-22 10:42:08 +00:00
fix: github rate limiter with multiple PATs
This commit is contained in:
parent
2efb399f33
commit
3d8dea90e2
@ -18,7 +18,9 @@ module.exports = async (req, res) => {
|
|||||||
} = req.query;
|
} = req.query;
|
||||||
let stats;
|
let stats;
|
||||||
|
|
||||||
|
res.setHeader("Cache-Control", "public, max-age=300");
|
||||||
res.setHeader("Content-Type", "image/svg+xml");
|
res.setHeader("Content-Type", "image/svg+xml");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
stats = await fetchStats(username);
|
stats = await fetchStats(username);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -14,6 +14,8 @@ module.exports = async (req, res) => {
|
|||||||
} = req.query;
|
} = req.query;
|
||||||
|
|
||||||
let repoData;
|
let repoData;
|
||||||
|
|
||||||
|
res.setHeader("Cache-Control", "public, max-age=300");
|
||||||
res.setHeader("Content-Type", "image/svg+xml");
|
res.setHeader("Content-Type", "image/svg+xml");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -5,8 +5,9 @@ async function fetchRepo(username, reponame) {
|
|||||||
throw new Error("Invalid username or reponame");
|
throw new Error("Invalid username or reponame");
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await request({
|
const res = await request(
|
||||||
query: `
|
{
|
||||||
|
query: `
|
||||||
fragment RepoInfo on Repository {
|
fragment RepoInfo on Repository {
|
||||||
name
|
name
|
||||||
stargazers {
|
stargazers {
|
||||||
@ -33,11 +34,15 @@ async function fetchRepo(username, reponame) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
variables: {
|
variables: {
|
||||||
login: username,
|
login: username,
|
||||||
repo: reponame,
|
repo: reponame,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
{
|
||||||
|
Authorization: `bearer ${process.env.PAT_1}`,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
|
|
||||||
|
@ -2,25 +2,25 @@ const { request } = require("./utils");
|
|||||||
const calculateRank = require("./calculateRank");
|
const calculateRank = require("./calculateRank");
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
|
|
||||||
async function fetchStats(username) {
|
// creating a fetcher function to reduce duplication
|
||||||
if (!username) throw Error("Invalid username");
|
const fetcher = (username, token) => {
|
||||||
|
return request(
|
||||||
const res = await request({
|
{
|
||||||
query: `
|
query: `
|
||||||
query userInfo($login: String!) {
|
query userInfo($login: String!) {
|
||||||
user(login: $login) {
|
user(login: $login) {
|
||||||
name
|
name
|
||||||
login
|
login
|
||||||
repositoriesContributedTo(first: 100, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
|
|
||||||
totalCount
|
|
||||||
}
|
|
||||||
contributionsCollection {
|
contributionsCollection {
|
||||||
totalCommitContributions
|
totalCommitContributions
|
||||||
}
|
}
|
||||||
pullRequests(first: 100) {
|
repositoriesContributedTo(first: 1, contributionTypes: [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]) {
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
issues(first: 100) {
|
pullRequests(first: 1) {
|
||||||
|
totalCount
|
||||||
|
}
|
||||||
|
issues(first: 1) {
|
||||||
totalCount
|
totalCount
|
||||||
}
|
}
|
||||||
followers {
|
followers {
|
||||||
@ -36,9 +36,45 @@ async function fetchStats(username) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
variables: { login: 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 = {
|
const stats = {
|
||||||
name: "",
|
name: "",
|
||||||
@ -47,12 +83,14 @@ async function fetchStats(username) {
|
|||||||
totalIssues: 0,
|
totalIssues: 0,
|
||||||
totalStars: 0,
|
totalStars: 0,
|
||||||
contributedTo: 0,
|
contributedTo: 0,
|
||||||
rank: "C",
|
rank: { level: "C", score: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let res = await retryer(username, RETRIES);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
console.log(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;
|
const user = res.data.data.user;
|
||||||
|
12
src/utils.js
12
src/utils.js
@ -33,13 +33,13 @@ function isValidHexColor(hexColor) {
|
|||||||
).test(hexColor);
|
).test(hexColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function request(data) {
|
function request(data, headers) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios({
|
axios({
|
||||||
url: "https://api.github.com/graphql",
|
url: "https://api.github.com/graphql",
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `bearer ${process.env.GITHUB_TOKEN}`,
|
...headers,
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
@ -48,4 +48,10 @@ function request(data) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { renderError, kFormatter, encodeHTML, isValidHexColor, request };
|
module.exports = {
|
||||||
|
renderError,
|
||||||
|
kFormatter,
|
||||||
|
encodeHTML,
|
||||||
|
isValidHexColor,
|
||||||
|
request,
|
||||||
|
};
|
||||||
|
@ -74,7 +74,7 @@ describe("Test fetchStats", () => {
|
|||||||
mock.onPost("https://api.github.com/graphql").reply(200, error);
|
mock.onPost("https://api.github.com/graphql").reply(200, error);
|
||||||
|
|
||||||
await expect(fetchStats("anuraghazra")).rejects.toThrow(
|
await expect(fetchStats("anuraghazra")).rejects.toThrow(
|
||||||
"Could not fetch user"
|
"Could not resolve to a User with the login of 'noname'."
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user