@@ -7,9 +7,11 @@ use reqwest::{
7
7
} ;
8
8
use serde:: Deserialize ;
9
9
use std:: collections:: HashSet ;
10
+ use std:: str:: FromStr ;
10
11
11
12
use crate :: repositories:: {
12
- FetchRepositoriesResult , Repository , RepositoryForge , RepositoryName , APP_USER_AGENT ,
13
+ FetchRepositoriesResult , RateLimitReached , Repository , RepositoryForge , RepositoryName ,
14
+ APP_USER_AGENT ,
13
15
} ;
14
16
15
17
const GRAPHQL_UPDATE : & str = "query($ids: [ID!]!) {
@@ -76,18 +78,19 @@ impl RepositoryForge for GitLab {
76
78
}
77
79
78
80
fn chunk_size ( & self ) -> usize {
79
- 5
81
+ 100
80
82
}
81
83
82
84
fn fetch_repository ( & self , name : & RepositoryName ) -> Result < Option < Repository > > {
83
85
let project_path = format ! ( "{}/{}" , name. owner, name. repo) ;
84
86
// Fetch the latest information from the Gitlab API.
85
- let response: GraphResponse < GraphProjectNode > = self . graphql (
87
+ let response: ( GraphResponse < GraphProjectNode > , Option < usize > ) = self . graphql (
86
88
GRAPHQL_SINGLE ,
87
89
serde_json:: json!( {
88
90
"fullPath" : & project_path,
89
91
} ) ,
90
92
) ?;
93
+ let ( response, rate_limit) = response;
91
94
if let Some ( repo) = response. data . and_then ( |d| d. project ) {
92
95
Ok ( Some ( Repository {
93
96
id : repo. id ,
@@ -98,18 +101,24 @@ impl RepositoryForge for GitLab {
98
101
forks : repo. forks_count ,
99
102
issues : repo. open_issues_count . unwrap_or ( 0 ) ,
100
103
} ) )
104
+ } else if rate_limit. map ( |x| x < 1 ) . unwrap_or ( false ) {
105
+ Err ( RateLimitReached . into ( ) )
101
106
} else {
102
107
Ok ( None )
103
108
}
104
109
}
105
110
106
111
fn fetch_repositories ( & self , ids : & [ String ] ) -> Result < FetchRepositoriesResult > {
107
- let response: GraphResponse < GraphProjects < Option < GraphProject > > > = self . graphql (
112
+ let response: (
113
+ GraphResponse < GraphProjects < Option < GraphProject > > > ,
114
+ Option < usize > ,
115
+ ) = self . graphql (
108
116
GRAPHQL_UPDATE ,
109
117
serde_json:: json!( {
110
118
"ids" : ids,
111
119
} ) ,
112
120
) ?;
121
+ let ( response, rate_limit) = response;
113
122
let mut ret = FetchRepositoriesResult :: default ( ) ;
114
123
// When gitlab doesn't find an ID, it simply doesn't list it. So we need to actually check
115
124
// which nodes remain at the end to delete their DB entry.
@@ -136,6 +145,10 @@ impl RepositoryForge for GitLab {
136
145
}
137
146
}
138
147
148
+ if ret. present . is_empty ( ) && rate_limit. map ( |x| x < 1 ) . unwrap_or ( false ) {
149
+ return Err ( RateLimitReached . into ( ) ) ;
150
+ }
151
+
139
152
// Those nodes were not returned by gitlab, meaning they don't exist (anymore?).
140
153
ret. missing = node_ids. into_iter ( ) . map ( |s| s. to_owned ( ) ) . collect ( ) ;
141
154
@@ -151,24 +164,29 @@ impl GitLab {
151
164
& self ,
152
165
query : & str ,
153
166
variables : impl serde:: Serialize ,
154
- ) -> Result < GraphResponse < T > > {
155
- Ok ( self
167
+ ) -> Result < ( GraphResponse < T > , Option < usize > ) > {
168
+ let res = self
156
169
. client
157
170
. post ( & format ! ( "https://{}/api/graphql" , self . host) )
158
171
. json ( & serde_json:: json!( {
159
172
"query" : query,
160
173
"variables" : variables,
161
174
} ) )
162
175
. send ( ) ?
163
- . error_for_status ( ) ?
164
- . json ( ) ?)
176
+ . error_for_status ( ) ?;
177
+ // There are a few other header values that might interesting so keeping them here:
178
+ // * RateLimit-Observed: '1'
179
+ // * RateLimit-Remaining: '1999'
180
+ // * RateLimit-ResetTime: 'Wed, 10 Feb 2021 21:31:42 GMT'
181
+ // * RateLimit-Limit: '2000'
182
+ let rate_limit = res
183
+ . headers ( )
184
+ . get ( "RateLimit-Remaining" )
185
+ . and_then ( |x| usize:: from_str ( x. to_str ( ) . ok ( ) ?) . ok ( ) ) ;
186
+ Ok ( ( res. json ( ) ?, rate_limit) )
165
187
}
166
188
}
167
189
168
- #[ derive( Debug , failure:: Fail ) ]
169
- #[ fail( display = "rate limit reached" ) ]
170
- struct RateLimitReached ;
171
-
172
190
#[ derive( Debug , Deserialize ) ]
173
191
struct GraphProjects < T > {
174
192
projects : GraphNodes < T > ,
0 commit comments