Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
github
hub
提交
ea016182
H
hub
项目概览
github
/
hub
9 个月 前同步成功
通知
3
Star
22523
Fork
2406
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
H
hub
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
ea016182
编写于
10月 30, 2019
作者:
M
Mislav Marohnić
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[api] Clean up `--rate-limit` implementation
上级
11e81b00
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
46 addition
and
97 deletion
+46
-97
commands/api.go
commands/api.go
+15
-32
features/api.feature
features/api.feature
+8
-65
github/http.go
github/http.go
+23
-0
未找到文件。
commands/api.go
浏览文件 @
ea016182
...
...
@@ -250,8 +250,7 @@ func apiCommand(_ *Command, args *Args) {
args
.
NoForward
()
requestLoop
:=
true
for
requestLoop
{
for
{
response
,
err
:=
gh
.
GenericAPIRequest
(
method
,
path
,
body
,
headers
,
cacheTTL
)
utils
.
Check
(
err
)
success
:=
response
.
StatusCode
<
300
...
...
@@ -285,7 +284,6 @@ func apiCommand(_ *Command, args *Args) {
os
.
Exit
(
22
)
}
requestLoop
=
false
if
paginate
{
if
isGraphQL
&&
hasNextPage
&&
endCursor
!=
""
{
if
v
,
ok
:=
params
[
"variables"
];
ok
{
...
...
@@ -295,47 +293,32 @@ func apiCommand(_ *Command, args *Args) {
variables
:=
map
[
string
]
interface
{}{
"endCursor"
:
endCursor
}
params
[
"variables"
]
=
variables
}
requestLoop
=
true
goto
next
}
else
if
nextLink
:=
response
.
Link
(
"next"
);
nextLink
!=
""
{
path
=
nextLink
requestLoop
=
true
goto
next
}
}
if
requestLoop
&&
!
parseJSON
{
break
next
:
if
!
parseJSON
{
fmt
.
Fprintf
(
out
,
"
\n
"
)
}
if
requestLoop
&&
rateLimit
{
var
rateLimitLeft
=
-
1
var
rateLimitResetMs
=
-
1
var
atoiErr
error
if
xRateLimitLeft
:=
response
.
Header
.
Get
(
rateLimitRemainingHeader
);
len
(
xRateLimitLeft
)
!=
0
{
if
rateLimitLeft
,
atoiErr
=
strconv
.
Atoi
(
xRateLimitLeft
);
atoiErr
!=
nil
{
ui
.
Errorf
(
"Unable to parse header
\"
%s
\"
:
\"
%s
\"
as an int"
,
rateLimitRemainingHeader
,
xRateLimitLeft
)
rateLimitLeft
=
-
1
}
}
if
xRateLimitReset
:=
response
.
Header
.
Get
(
rateLimitResetHeader
);
len
(
xRateLimitReset
)
!=
0
{
if
rateLimitResetMs
,
atoiErr
=
strconv
.
Atoi
(
xRateLimitReset
);
atoiErr
!=
nil
{
ui
.
Errorf
(
"Unable to parse header
\"
%s
\"
:
\"
%s
\"
as an int"
,
rateLimitResetHeader
,
xRateLimitReset
)
rateLimitResetMs
=
-
1
}
}
if
rateLimitResetMs
!=
-
1
&&
rateLimitLeft
==
0
{
rollover
:=
time
.
Unix
(
int64
(
rateLimitResetMs
)
+
1
,
0
)
ui
.
Errorf
(
"Pausing until %v for Rate Limit Reset ...
\n
"
,
rollover
)
time
.
Sleep
(
time
.
Until
(
rollover
))
}
if
rateLimit
&&
response
.
RateLimitRemaining
()
==
0
{
resetAt
:=
response
.
RateLimitReset
()
rollover
:=
time
.
Unix
(
int64
(
resetAt
)
+
1
,
0
)
ui
.
Errorf
(
"API rate limit reached; pausing until %v ...
\n
"
,
rollover
)
time
.
Sleep
(
time
.
Until
(
rollover
))
}
}
}
const
(
trueVal
=
"true"
falseVal
=
"false"
nilVal
=
"null"
rateLimitRemainingHeader
=
"X-Ratelimit-Remaining"
rateLimitResetHeader
=
"X-Ratelimit-Reset"
trueVal
=
"true"
falseVal
=
"false"
nilVal
=
"null"
)
func
magicValue
(
value
string
)
interface
{}
{
...
...
features/api.feature
浏览文件 @
ea016182
...
...
@@ -422,75 +422,18 @@ Feature: hub api
When
I run `hub api -t count --cache 5`
Then
it should pass with
".count 2"
Scenario
:
Honor rate limit
by sleeping
Scenario
:
Honor rate limit
with pagination
Given the GitHub API server
:
"""
get('/hello') {
page = (params[:page] || 1).to_i
response.headers['X-Ratelimit-Remaining'] = '0'
# it doesn't matter, cucumber blanks the .sleep anyway
response.headers['X-Ratelimit-Reset'] = '1'
response.headers['Link'] = %(</hello?page=2>; rel="next") if page < 2
if page < 2
response.headers['X-Ratelimit-Remaining'] = '0'
response.headers['X-Ratelimit-Reset'] = Time.now.utc.to_i.to_s
response.headers['Link'] = %(</hello?page=#{page+1}>; rel="next")
end
json [{}]
}
"""
When
I run `hub api --rate-limit --paginate hello`
Then
the stderr should contain
"Pausing until "
Given the GitHub API server
:
"""
get('/hello') {
page = (params[:page] || 1).to_i
response.headers['X-Ratelimit-Remaining'] = '0'
# it doesn't matter, cucumber blanks the .sleep anyway
response.headers['X-Ratelimit-Reset'] = '9999999999'
response.headers['Link'] = %(</hello2>; rel="next")
json [{}]
}
get('/hello2') {
status 403
}
"""
When
I run `hub api --paginate hello`
Then
the exit status should be 22
And
the stderr should contain exactly
""
Given the GitHub API server
:
"""
get('/hello') {
page = (params[:page] || 1).to_i
response.headers['X-Ratelimit-Remaining'] = 'hello world'
response.headers['X-Ratelimit-Reset'] = 'yankee doodle'
response.headers['Link'] = %(</hello2>; rel="next")
json [{:page => 1}]
}
get('/hello2') {
json [{:page => 2}]
}
"""
When
I run `hub api --rate-limit --paginate hello`
Then the stdout should contain exactly
:
"""
[{"page":1}]
[{"page":2}]
"""
And
the stderr should contain
"Unable to parse"
Given the GitHub API server
:
"""
get('/hello') {
response.headers['Link'] = %(</hello2>; rel="next")
json [{:page => 1}]
}
get('/hello2') {
json [{:page => 2}]
}
"""
# rate-limit should behave rationally even when missing the headers
When
I run `hub api --rate-limit --paginate hello`
Then the stdout should contain exactly
:
"""
[{"page":1}]
[{"page":2}]
"""
And
the stderr should contain exactly
""
When
I successfully run `hub api --rate-limit --paginate hello`
Then
the stderr should contain
"API rate limit reached; pausing until "
github/http.go
浏览文件 @
ea016182
...
...
@@ -32,6 +32,11 @@ const checksType = "application/vnd.github.antiope-preview+json;charset=utf-8"
const
draftsType
=
"application/vnd.github.shadow-cat-preview+json;charset=utf-8"
const
cacheVersion
=
2
const
(
rateLimitRemainingHeader
=
"X-Ratelimit-Remaining"
rateLimitResetHeader
=
"X-Ratelimit-Reset"
)
var
inspectHeaders
=
[]
string
{
"Authorization"
,
"X-GitHub-OTP"
,
...
...
@@ -517,3 +522,21 @@ func (res *simpleResponse) Link(name string) string {
}
return
""
}
func
(
res
*
simpleResponse
)
RateLimitRemaining
()
int
{
if
v
:=
res
.
Header
.
Get
(
rateLimitRemainingHeader
);
len
(
v
)
>
0
{
if
num
,
err
:=
strconv
.
Atoi
(
v
);
err
==
nil
{
return
num
}
}
return
-
1
}
func
(
res
*
simpleResponse
)
RateLimitReset
()
int
{
if
v
:=
res
.
Header
.
Get
(
rateLimitResetHeader
);
len
(
v
)
>
0
{
if
ts
,
err
:=
strconv
.
Atoi
(
v
);
err
==
nil
{
return
ts
}
}
return
-
1
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录