22import fs from 'fs' ;
33import path from 'path' ;
44import { promisify } from 'util' ;
5+ import fetch from 'node-fetch' ;
56import lodash from 'lodash' ;
67import { fileURLToPath } from 'url' ;
78
@@ -22,22 +23,7 @@ const absoluteFilename = path.resolve(
2223 filename
2324) ;
2425
25- let graphqlEndpoint = 'https://api.opencollective.com/graphql/v2' ;
26-
27- if ( process . env . OPENCOLLECTIVE_API_KEY ) {
28- // rate limit is 100 requests per minute with personal access token
29- // rate limit is 10 requests per minute without personal access token
30- console . log (
31- 'Using personal access token to fetch supporters from OpenCollective'
32- ) ;
33- // by default a personal access token of @chenxsan was used as I don't have access to the webpack one
34- // @doc https://graphql-docs-v2.opencollective.com/access#with-a-personal-token
35- graphqlEndpoint = `https://api.opencollective.com/graphql/v2?personalToken=${ process . env . OPENCOLLECTIVE_API_KEY } ` ;
36- } else {
37- console . log (
38- 'No personal access token found, using public API to fetch supporters from OpenCollective'
39- ) ;
40- }
26+ const graphqlEndpoint = 'https://api.opencollective.com/graphql/v2' ;
4127
4228// https://github.com/opencollective/opencollective-api/blob/master/server/graphql/v2/query/TransactionsQuery.ts#L81
4329const graphqlPageSize = 1000 ;
@@ -105,72 +91,26 @@ const getAllNodes = async (graphqlQuery, getNodes) => {
10591
10692 let allNodes = [ ] ;
10793
108- let limit = 10 ,
109- remaining = 10 ,
110- reset ;
111- if ( process . env . OPENCOLLECTIVE_API_KEY ) {
112- limit = 100 ;
113- remaining = 100 ;
114- }
11594 // Handling pagination if necessary
11695 // eslint-disable-next-line
11796 while ( true ) {
118- if ( remaining === 0 ) {
119- console . log ( `Rate limit exceeded. Sleeping until ${ new Date ( reset ) } .` ) ;
120- await new Promise ( ( resolve ) =>
121- setTimeout ( resolve , reset - Date . now ( ) + 100 )
122- ) ;
123- }
12497 const result = await fetch ( graphqlEndpoint , {
12598 method : 'POST' ,
12699 body : JSON . stringify ( body ) ,
127100 headers : {
128101 'Content-Type' : 'application/json' ,
129102 } ,
130- } ) . then ( async ( response ) => {
131- if ( response . headers . get ( 'content-type' ) . includes ( 'json' ) ) {
132- const json = await response . json ( ) ;
133- console . log ( 'json' , json ) ;
134- if ( json . error ) {
135- // when rate limit exceeded, api won't return headers data like x-ratelimit-limit, etc.
136- remaining = 0 ;
137- reset = Date . now ( ) + 1000 * 60 ; // 1 minute
138- } else {
139- limit = response . headers . get ( 'x-ratelimit-limit' ) * 1 ;
140- remaining = response . headers . get ( 'x-ratelimit-remaining' ) * 1 ;
141- reset = response . headers . get ( 'x-ratelimit-reset' ) * 1000 ;
142- console . log (
143- `Rate limit: ${ remaining } /${ limit } remaining. Reset in ${ new Date (
144- reset
145- ) } `
146- ) ;
147- }
148- return json ;
149- } else {
150- // utilities/fetch-supporters: SyntaxError: Unexpected token < in JSON at position 0
151- console . log ( 'something wrong when fetching supporters' ) ;
152- return {
153- error : {
154- message : await response . text ( ) ,
155- } ,
156- } ;
157- }
158- } ) ;
159- // when rate limit exceeded, api will return {error: {message: ''}}
160- // but we could hopefully avoid rate limit by sleeping in the beginning of the loop
161- // however, when there're multiple task running simultaneously, it's still possible to hit the rate limit
162- if ( result . error ) {
163- console . log ( 'error' , result . error ) ;
164- // let the loop continue
103+ } ) . then ( ( response ) => response . json ( ) ) ;
104+ console . log ( result ) ;
105+ if ( result . errors ) throw new Error ( result . errors [ 0 ] . message ) ;
106+ const nodes = getNodes ( result . data ) ;
107+ allNodes = [ ...allNodes , ...nodes ] ;
108+ body . variables . offset += graphqlPageSize ;
109+ if ( nodes . length < graphqlPageSize ) {
110+ return allNodes ;
165111 } else {
166- const nodes = getNodes ( result . data ) ;
167- allNodes = [ ...allNodes , ...nodes ] ;
168- body . variables . offset += graphqlPageSize ;
169- if ( nodes . length < graphqlPageSize ) {
170- return allNodes ;
171- } else {
172- // more nodes to fetch
173- }
112+ // sleep for a while
113+ await new Promise ( ( resolve ) => setTimeout ( resolve , 6000 ) ) ;
174114 }
175115 }
176116} ;
0 commit comments