1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Github OAuth tokens management
19 # When using batch mode with the `github` API, we can rapidly reach the rate
20 # limit allowed by Github.
22 # One solution consists in using a wallet of tokens so we can rely on more than
23 # one token and switch them when one become exhausted.
25 # ## Using the Github wallet to check tokens
27 # One functionality of the wallet is to check the validity of a token against
28 # the API. `check_token` will return false if a token is invalid or exhausted.
31 # var wallet = new GithubWallet
32 # assert not wallet.check_token("this is a bad token")
37 # The wallet can also be used to store tokens and check all of them.
40 # wallet = new GithubWallet
41 # wallet.add "some token"
42 # wallet.add "some other token"
48 # wallet = new GithubWallet(["token 1", "token 2"])
51 # The `show_status` method can be used to display a summary of the validity of
52 # each token in the wallet.
58 # Will display something like this:
66 # ## Using the wallet to obtain a Github API client
68 # Using the wallet you can cycle through tokens and obtain a new Github API client
69 # instance with a fresh rate limit.
72 # wallet = new GithubWallet(["token 1", "token 2"])
73 # var api = wallet.api
76 # The wallet will automatically cycle through the registered tokens to find one
79 # If no valid token is found after all of them was tried, the wallet returns a
80 # client based on the last tried one.
86 # Github OAuth tokens wallet
90 var tokens
= new Array[String] is optional
92 # Logger used to display info about tokens state
93 var logger
= new Logger is optional
, writable
95 # Add a new token in the wallet
96 fun add
(token
: String) do tokens
.add token
98 # Get an instance of GithubAPI based on the next available token.
100 # If no token is found, return an api based on the last exhausted token.
101 fun api
: GithubAPI do
103 if tokens
.is_empty
then
104 logger
.warn
"No tokens, using `get_github_oauth`"
105 token
= get_github_oauth
107 token
= get_next_token
109 while not check_token
(token
) do
110 if tried
>= tokens
.length
- 1 then
111 logger
.warn
"Exhausted all tokens, using {token}"
115 token
= get_next_token
118 var api
= new GithubAPI(token
)
119 api
.enable_cache
= true
123 # The current index in the `tokens` array
124 private var current_index
= 0
126 # The current token in the `tokens` array based on `current_index`
127 fun current_token
: String do return tokens
[current_index
]
129 # Get the next token in token `array` based on `current_token`.
131 # If the end of the list is reached, start again from the begining.
132 fun get_next_token
: String do
133 if tokens
.is_empty
then
134 return get_github_oauth
136 var token
= current_token
138 if current_index
< tokens
.length
- 1 then
146 # Check if a token is valid
147 fun check_token
(token
: String): Bool do
148 logger
.debug
"Try token {token}"
149 var api
= new GithubAPI(token
)
151 return not api
.was_error
154 # Show wallet status in console
155 fun show_status
(no_color
: nullable Bool) do
156 no_color
= no_color
or else false
158 if tokens
.is_empty
then
159 print
"Wallet is empty"
162 print
"Wallet ({tokens.length} tokens):"
163 for token
in tokens
do
165 if check_token
(token
) then
166 status
= if no_color
then "OK" else "OK".green
168 status
= if no_color
then "KO" else "KO".red
170 print
" * [{status}] {token}"