{"action":"created","comment":{"url":"https://api.github.com/repos/nitlang/nit/pulls/comments/73940948","id":73940948,"diff_hunk":"@@ -0,0 +1,179 @@\n+# This file is part of NIT ( http://www.nitlanguage.org ).\n+#\n+# Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+#     http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+module wallet\n+\n+import github\n+import console\n+\n+# Github OAuth tokens management\n+#\n+# When using batch mode with the `github` API, we can rapidly reach the rate\n+# limit allowed by Github.\n+#\n+# One solution consists in using a wallet of tokens so we can rely on more than\n+# one token and switch them when one become exhausted.\n+#\n+# ## Using the Github wallet to check tokens\n+#\n+# One functionality of the wallet is to check the validity of a token against\n+# the API. `check_token` will return false if a token is invalid or exhausted.\n+#\n+# ~~~\n+# var wallet = new GithubWallet\n+# assert not wallet.check_token(\"this is a bad token\")\n+# ~~~\n+#\n+# ## Storing tokens\n+#\n+# The wallet can also be used to store tokens and check all of them.\n+#\n+# ~~~\n+# wallet = new GithubWallet\n+# wallet.add \"some token\"\n+# wallet.add \"some other token\"\n+# ~~~\n+#\n+# or\n+#\n+# ~~~\n+# wallet = new GithubWallet.from_tokens([\"token 1\", \"token 2\"])\n+# ~~~\n+#\n+# The `show_status` method can be used to display a summary of the validity of\n+# each token in the wallet.\n+#\n+# ~~~\n+# wallet.show_status\n+# ~~~\n+#\n+# Will display something like this:\n+#\n+# ~~~raw\n+# Wallet (2 tokens):\n+#  * [OK] token 1\n+#  * [KO] token 2\n+# ~~~\n+#\n+# ## Using the wallet to obtain a Github API client\n+#\n+# Using the wallet you can cycle through tokens and obtain a new Github API client\n+# instance with a fresh rate limit.\n+#\n+# ~~~\n+# wallet = new GithubWallet.from_tokens([\"token 1\", \"token 2\"])\n+# var api = wallet.api\n+# ~~~\n+#\n+# The wallet will automatically cycle through the registered tokens to find one\n+# that works.\n+#\n+# To avoid infinite loop, if not valid token is found after all of them was tried,\n+# the wallet returns an client based on the last tried token.\n+class GithubWallet\n+\n+\t# Github API tokens\n+\tvar tokens = new Array[String]\n+\n+\t# Init `self` from an array of tokens\n+\tinit from_tokens(tokens: Array[String]) do self.tokens = tokens\n+\n+\t# Do not use colors in console output\n+\tvar no_colors = false is writable\n+\n+\t# Display debug information about the token processing\n+\tvar verbose = false is writable\n+\n+\t# Add a new token in the wallet\n+\tfun add(token: String) do tokens.add token\n+\n+\t# Get an instance of GithubAPI based on the next available token.\n+\t#\n+\t# If no token is found, return an api based on the last exhausted token.\n+\tfun api: GithubAPI do\n+\t\tvar token\n+\t\tif tokens.is_empty then\n+\t\t\tmessage \"No tokens, using `get_github_oauth`\"\n+\t\t\ttoken = get_github_oauth\n+\t\telse\n+\t\t\ttoken = get_next_token\n+\t\t\tvar tried = 0\n+\t\t\twhile not check_token(token) do\n+\t\t\t\tif tried >= tokens.length - 1 then\n+\t\t\t\t\tmessage \"Exhausted all tokens, using {token}\"\n+\t\t\t\t\tbreak\n+\t\t\t\tend\n+\t\t\t\ttried += 1\n+\t\t\t\ttoken = get_next_token\n+\t\t\tend\n+\t\tend\n+\t\tvar api = new GithubAPI(token)\n+\t\tapi.enable_cache = true\n+\t\treturn api\n+\tend\n+\n+\t# The current index in the `tokens` array\n+\tprivate var current_index = 0\n+\n+\t# The current token in the `tokens` array based on `current_index`\n+\tfun current_token: String do return tokens[current_index]\n+\n+\t# Get the next token in token `array` based on `current_token`.\n+\t#\n+\t# If the end of the list is reached, start again from the begining.\n+\tfun get_next_token: String do\n+\t\tif tokens.is_empty then\n+\t\t\treturn get_github_oauth\n+\t\tend\n+\t\tvar token = current_token\n+\n+\t\tif current_index < tokens.length - 1 then\n+\t\t\tcurrent_index += 1\n+\t\telse\n+\t\t\tcurrent_index = 0\n+\t\tend\n+\t\treturn token\n+\tend\n+\n+\t# Check if a token is valid\n+\tfun check_token(token: String): Bool do\n+\t\tmessage \"Try token {token}\"\n+\t\tvar api = new GithubAPI(token)\n+\t\tapi.load_repo(\"nitlang/nit\")","path":"lib/github/wallet.nit","position":156,"original_position":155,"commit_id":"8b5a29f1705519e74983e2b42136ef4ab369b28e","original_commit_id":"32c5853f477973bcdd3015c65a0f7ef1d9d34552","user":{"login":"jcbrinfo","id":6044484,"avatar_url":"https://avatars.githubusercontent.com/u/6044484?v=3","gravatar_id":"","url":"https://api.github.com/users/jcbrinfo","html_url":"https://github.com/jcbrinfo","followers_url":"https://api.github.com/users/jcbrinfo/followers","following_url":"https://api.github.com/users/jcbrinfo/following{/other_user}","gists_url":"https://api.github.com/users/jcbrinfo/gists{/gist_id}","starred_url":"https://api.github.com/users/jcbrinfo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jcbrinfo/subscriptions","organizations_url":"https://api.github.com/users/jcbrinfo/orgs","repos_url":"https://api.github.com/users/jcbrinfo/repos","events_url":"https://api.github.com/users/jcbrinfo/events{/privacy}","received_events_url":"https://api.github.com/users/jcbrinfo/received_events","type":"User","site_admin":false},"body":"Why not probing @octocat?","created_at":"2016-08-08T19:46:42Z","updated_at":"2016-08-08T19:46:42Z","html_url":"https://github.com/nitlang/nit/pull/2243#discussion_r73940948","pull_request_url":"https://api.github.com/repos/nitlang/nit/pulls/2243","_links":{"self":{"href":"https://api.github.com/repos/nitlang/nit/pulls/comments/73940948"},"html":{"href":"https://github.com/nitlang/nit/pull/2243#discussion_r73940948"},"pull_request":{"href":"https://api.github.com/repos/nitlang/nit/pulls/2243"}}},"pull_request":{"url":"https://api.github.com/repos/nitlang/nit/pulls/2243","id":80494224,"html_url":"https://github.com/nitlang/nit/pull/2243","diff_url":"https://github.com/nitlang/nit/pull/2243.diff","patch_url":"https://github.com/nitlang/nit/pull/2243.patch","issue_url":"https://api.github.com/repos/nitlang/nit/issues/2243","number":2243,"state":"open","locked":false,"title":"lib/github: introduce GithubWallet","user":{"login":"Morriar","id":583144,"avatar_url":"https://avatars.githubusercontent.com/u/583144?v=3","gravatar_id":"","url":"https://api.github.com/users/Morriar","html_url":"https://github.com/Morriar","followers_url":"https://api.github.com/users/Morriar/followers","following_url":"https://api.github.com/users/Morriar/following{/other_user}","gists_url":"https://api.github.com/users/Morriar/gists{/gist_id}","starred_url":"https://api.github.com/users/Morriar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Morriar/subscriptions","organizations_url":"https://api.github.com/users/Morriar/orgs","repos_url":"https://api.github.com/users/Morriar/repos","events_url":"https://api.github.com/users/Morriar/events{/privacy}","received_events_url":"https://api.github.com/users/Morriar/received_events","type":"User","site_admin":false},"body":"## Github OAuth tokens management\r\n\r\nWhen using batch mode with the `github` API, we can rapidly reach the rate\r\nlimit allowed by Github.\r\n\r\nOne solution consists in using a wallet of tokens so we can rely on more than\r\none token and switch them when one become exhausted.\r\n\r\n### Using the Github wallet to check tokens\r\n\r\nOne functionality of the wallet is to check the validity of a token against\r\nthe API. `check_token` will return false if a token is invalid or exhausted.\r\n\r\n~~~nit\r\nvar wallet = new GithubWallet\r\nassert not wallet.check_token(\"this is a bad token\")\r\n~~~\r\n\r\n### Storing tokens\r\n\r\nThe wallet can also be used to store tokens and check all of them.\r\n\r\n~~~nit\r\nwallet = new GithubWallet\r\nwallet.add \"some token\"\r\nwallet.add \"some other token\"\r\n~~~\r\n\r\nor\r\n\r\n~~~nit\r\nwallet = new GithubWallet.from_tokens([\"token 1\", \"token 2\"])\r\n~~~\r\n\r\nThe `show_status` method can be used to display a summary of the validity of\r\neach token in the wallet.\r\n\r\n~~~nit\r\nwallet.show_status\r\n~~~\r\n\r\nWill display something like this:\r\n\r\n~~~raw\r\nWallet (2 tokens):\r\n * [OK] token 1\r\n * [KO] token 2\r\n~~~\r\n\r\n### Using the wallet to obtain a Github API client\r\n\r\nUsing the wallet you can cycle through tokens and obtain a new Github API client\r\ninstance with a fresh rate limit.\r\n\r\n~~~nit\r\nwallet = new GithubWallet.from_tokens([\"token 1\", \"token 2\"])\r\nvar api = wallet.api\r\n~~~\r\n\r\nThe wallet will automatically cycle through the registered tokens to find one\r\nthat works.\r\n\r\nTo avoid infinite loop, if not valid token is found after all of them was tried,\r\nthe wallet returns an client based on the last tried token.","created_at":"2016-08-08T17:59:56Z","updated_at":"2016-08-08T19:46:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0b13e6742c86012511f0512b2ef890ed0fdd776d","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/nitlang/nit/pulls/2243/commits","review_comments_url":"https://api.github.com/repos/nitlang/nit/pulls/2243/comments","review_comment_url":"https://api.github.com/repos/nitlang/nit/pulls/comments{/number}","comments_url":"https://api.github.com/repos/nitlang/nit/issues/2243/comments","statuses_url":"https://api.github.com/repos/nitlang/nit/statuses/8b5a29f1705519e74983e2b42136ef4ab369b28e","head":{"label":"Morriar:github-wallet","ref":"github-wallet","sha":"8b5a29f1705519e74983e2b42136ef4ab369b28e","user":{"login":"Morriar","id":583144,"avatar_url":"https://avatars.githubusercontent.com/u/583144?v=3","gravatar_id":"","url":"https://api.github.com/users/Morriar","html_url":"https://github.com/Morriar","followers_url":"https://api.github.com/users/Morriar/followers","following_url":"https://api.github.com/users/Morriar/following{/other_user}","gists_url":"https://api.github.com/users/Morriar/gists{/gist_id}","starred_url":"https://api.github.com/users/Morriar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Morriar/subscriptions","organizations_url":"https://api.github.com/users/Morriar/orgs","repos_url":"https://api.github.com/users/Morriar/repos","events_url":"https://api.github.com/users/Morriar/events{/privacy}","received_events_url":"https://api.github.com/users/Morriar/received_events","type":"User","site_admin":false},"repo":{"id":1456691,"name":"nit","full_name":"Morriar/nit","owner":{"login":"Morriar","id":583144,"avatar_url":"https://avatars.githubusercontent.com/u/583144?v=3","gravatar_id":"","url":"https://api.github.com/users/Morriar","html_url":"https://github.com/Morriar","followers_url":"https://api.github.com/users/Morriar/followers","following_url":"https://api.github.com/users/Morriar/following{/other_user}","gists_url":"https://api.github.com/users/Morriar/gists{/gist_id}","starred_url":"https://api.github.com/users/Morriar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Morriar/subscriptions","organizations_url":"https://api.github.com/users/Morriar/orgs","repos_url":"https://api.github.com/users/Morriar/repos","events_url":"https://api.github.com/users/Morriar/events{/privacy}","received_events_url":"https://api.github.com/users/Morriar/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Morriar/nit","description":"Nit language","fork":true,"url":"https://api.github.com/repos/Morriar/nit","forks_url":"https://api.github.com/repos/Morriar/nit/forks","keys_url":"https://api.github.com/repos/Morriar/nit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Morriar/nit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Morriar/nit/teams","hooks_url":"https://api.github.com/repos/Morriar/nit/hooks","issue_events_url":"https://api.github.com/repos/Morriar/nit/issues/events{/number}","events_url":"https://api.github.com/repos/Morriar/nit/events","assignees_url":"https://api.github.com/repos/Morriar/nit/assignees{/user}","branches_url":"https://api.github.com/repos/Morriar/nit/branches{/branch}","tags_url":"https://api.github.com/repos/Morriar/nit/tags","blobs_url":"https://api.github.com/repos/Morriar/nit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Morriar/nit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Morriar/nit/git/refs{/sha}","trees_url":"https://api.github.com/repos/Morriar/nit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Morriar/nit/statuses/{sha}","languages_url":"https://api.github.com/repos/Morriar/nit/languages","stargazers_url":"https://api.github.com/repos/Morriar/nit/stargazers","contributors_url":"https://api.github.com/repos/Morriar/nit/contributors","subscribers_url":"https://api.github.com/repos/Morriar/nit/subscribers","subscription_url":"https://api.github.com/repos/Morriar/nit/subscription","commits_url":"https://api.github.com/repos/Morriar/nit/commits{/sha}","git_commits_url":"https://api.github.com/repos/Morriar/nit/git/commits{/sha}","comments_url":"https://api.github.com/repos/Morriar/nit/comments{/number}","issue_comment_url":"https://api.github.com/repos/Morriar/nit/issues/comments{/number}","contents_url":"https://api.github.com/repos/Morriar/nit/contents/{+path}","compare_url":"https://api.github.com/repos/Morriar/nit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Morriar/nit/merges","archive_url":"https://api.github.com/repos/Morriar/nit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Morriar/nit/downloads","issues_url":"https://api.github.com/repos/Morriar/nit/issues{/number}","pulls_url":"https://api.github.com/repos/Morriar/nit/pulls{/number}","milestones_url":"https://api.github.com/repos/Morriar/nit/milestones{/number}","notifications_url":"https://api.github.com/repos/Morriar/nit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Morriar/nit/labels{/name}","releases_url":"https://api.github.com/repos/Morriar/nit/releases{/id}","deployments_url":"https://api.github.com/repos/Morriar/nit/deployments","created_at":"2011-03-08T22:16:33Z","updated_at":"2015-06-06T03:02:03Z","pushed_at":"2016-08-08T19:45:59Z","git_url":"git://github.com/Morriar/nit.git","ssh_url":"git@github.com:Morriar/nit.git","clone_url":"https://github.com/Morriar/nit.git","svn_url":"https://github.com/Morriar/nit","homepage":"http://nitlanguage.org","size":116573,"stargazers_count":3,"watchers_count":3,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":15,"forks":2,"open_issues":15,"watchers":3,"default_branch":"master"}},"base":{"label":"nitlang:master","ref":"master","sha":"9590a6f674a5ad792b80e79a3b0943624d34c78b","user":{"login":"nitlang","id":5420298,"avatar_url":"https://avatars.githubusercontent.com/u/5420298?v=3","gravatar_id":"","url":"https://api.github.com/users/nitlang","html_url":"https://github.com/nitlang","followers_url":"https://api.github.com/users/nitlang/followers","following_url":"https://api.github.com/users/nitlang/following{/other_user}","gists_url":"https://api.github.com/users/nitlang/gists{/gist_id}","starred_url":"https://api.github.com/users/nitlang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nitlang/subscriptions","organizations_url":"https://api.github.com/users/nitlang/orgs","repos_url":"https://api.github.com/users/nitlang/repos","events_url":"https://api.github.com/users/nitlang/events{/privacy}","received_events_url":"https://api.github.com/users/nitlang/received_events","type":"Organization","site_admin":false},"repo":{"id":328597,"name":"nit","full_name":"nitlang/nit","owner":{"login":"nitlang","id":5420298,"avatar_url":"https://avatars.githubusercontent.com/u/5420298?v=3","gravatar_id":"","url":"https://api.github.com/users/nitlang","html_url":"https://github.com/nitlang","followers_url":"https://api.github.com/users/nitlang/followers","following_url":"https://api.github.com/users/nitlang/following{/other_user}","gists_url":"https://api.github.com/users/nitlang/gists{/gist_id}","starred_url":"https://api.github.com/users/nitlang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nitlang/subscriptions","organizations_url":"https://api.github.com/users/nitlang/orgs","repos_url":"https://api.github.com/users/nitlang/repos","events_url":"https://api.github.com/users/nitlang/events{/privacy}","received_events_url":"https://api.github.com/users/nitlang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/nitlang/nit","description":"Nit language","fork":false,"url":"https://api.github.com/repos/nitlang/nit","forks_url":"https://api.github.com/repos/nitlang/nit/forks","keys_url":"https://api.github.com/repos/nitlang/nit/keys{/key_id}","collaborators_url":"https://api.github.com/repos/nitlang/nit/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/nitlang/nit/teams","hooks_url":"https://api.github.com/repos/nitlang/nit/hooks","issue_events_url":"https://api.github.com/repos/nitlang/nit/issues/events{/number}","events_url":"https://api.github.com/repos/nitlang/nit/events","assignees_url":"https://api.github.com/repos/nitlang/nit/assignees{/user}","branches_url":"https://api.github.com/repos/nitlang/nit/branches{/branch}","tags_url":"https://api.github.com/repos/nitlang/nit/tags","blobs_url":"https://api.github.com/repos/nitlang/nit/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/nitlang/nit/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/nitlang/nit/git/refs{/sha}","trees_url":"https://api.github.com/repos/nitlang/nit/git/trees{/sha}","statuses_url":"https://api.github.com/repos/nitlang/nit/statuses/{sha}","languages_url":"https://api.github.com/repos/nitlang/nit/languages","stargazers_url":"https://api.github.com/repos/nitlang/nit/stargazers","contributors_url":"https://api.github.com/repos/nitlang/nit/contributors","subscribers_url":"https://api.github.com/repos/nitlang/nit/subscribers","subscription_url":"https://api.github.com/repos/nitlang/nit/subscription","commits_url":"https://api.github.com/repos/nitlang/nit/commits{/sha}","git_commits_url":"https://api.github.com/repos/nitlang/nit/git/commits{/sha}","comments_url":"https://api.github.com/repos/nitlang/nit/comments{/number}","issue_comment_url":"https://api.github.com/repos/nitlang/nit/issues/comments{/number}","contents_url":"https://api.github.com/repos/nitlang/nit/contents/{+path}","compare_url":"https://api.github.com/repos/nitlang/nit/compare/{base}...{head}","merges_url":"https://api.github.com/repos/nitlang/nit/merges","archive_url":"https://api.github.com/repos/nitlang/nit/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/nitlang/nit/downloads","issues_url":"https://api.github.com/repos/nitlang/nit/issues{/number}","pulls_url":"https://api.github.com/repos/nitlang/nit/pulls{/number}","milestones_url":"https://api.github.com/repos/nitlang/nit/milestones{/number}","notifications_url":"https://api.github.com/repos/nitlang/nit/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/nitlang/nit/labels{/name}","releases_url":"https://api.github.com/repos/nitlang/nit/releases{/id}","deployments_url":"https://api.github.com/repos/nitlang/nit/deployments","created_at":"2009-10-06T15:03:00Z","updated_at":"2016-07-01T01:16:02Z","pushed_at":"2016-08-08T19:45:59Z","git_url":"git://github.com/nitlang/nit.git","ssh_url":"git@github.com:nitlang/nit.git","clone_url":"https://github.com/nitlang/nit.git","svn_url":"https://github.com/nitlang/nit","homepage":"http://nitlanguage.org","size":133677,"stargazers_count":146,"watchers_count":146,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":52,"mirror_url":null,"open_issues_count":158,"forks":52,"open_issues":158,"watchers":146,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/nitlang/nit/pulls/2243"},"html":{"href":"https://github.com/nitlang/nit/pull/2243"},"issue":{"href":"https://api.github.com/repos/nitlang/nit/issues/2243"},"comments":{"href":"https://api.github.com/repos/nitlang/nit/issues/2243/comments"},"review_comments":{"href":"https://api.github.com/repos/nitlang/nit/pulls/2243/comments"},"review_comment":{"href":"https://api.github.com/repos/nitlang/nit/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/nitlang/nit/pulls/2243/commits"},"statuses":{"href":"https://api.github.com/repos/nitlang/nit/statuses/8b5a29f1705519e74983e2b42136ef4ab369b28e"}}}}
{"actor":{"display_login":"jcbrinfo"}}