From 511f1312af2f01eaf24b92ed65629bccfe487144 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Sat, 11 Nov 2017 11:51:35 +0000 Subject: [PATCH] Complete rewrite using Rust --- .gitignore | 5 +++++ .travis.yml | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 19 +++++++++++++++++++ README.md | 39 ++++++++++++++++++++++++++++++++------- appveyor.yml | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ci/before_deploy.ps1 | 23 +++++++++++++++++++++++ ci/before_deploy.sh | 33 +++++++++++++++++++++++++++++++++ ci/install.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++++ ci/script.sh | 24 ++++++++++++++++++++++++ common.js | 12 ------------ package.json | 20 -------------------- reaper.js | 46 ---------------------------------------------- src/main.rs | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 585 insertions(+), 85 deletions(-) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Cargo.toml create mode 100644 appveyor.yml create mode 100644 ci/before_deploy.ps1 create mode 100644 ci/before_deploy.sh create mode 100644 ci/install.sh create mode 100644 ci/script.sh delete mode 100644 common.js delete mode 100644 package.json delete mode 100644 reaper.js create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c21e6c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +**/*.rs.bk +Cargo.lock +/target/ +**/*.rs.bk diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4492818 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,134 @@ +# Based on the "trust" template v0.1.1 +# https://github.com/japaric/trust/tree/v0.1.1 + +dist: trusty +language: rust +services: docker +sudo: required + +# TODO Rust builds on stable by default, this can be +# overridden on a case by case basis down below. + +env: + global: + # TODO Update this to match the name of your project. + - CRATE_NAME=reaper + +matrix: + # TODO These are all the build jobs. Adjust as necessary. Comment out what you + # don't need + include: + # Android + - env: TARGET=aarch64-linux-android DISABLE_TESTS=1 + - env: TARGET=arm-linux-androideabi DISABLE_TESTS=1 + - env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1 + - env: TARGET=i686-linux-android DISABLE_TESTS=1 + - env: TARGET=x86_64-linux-android DISABLE_TESTS=1 + + # iOS + - env: TARGET=aarch64-apple-ios DISABLE_TESTS=1 + os: osx + - env: TARGET=armv7-apple-ios DISABLE_TESTS=1 + os: osx + - env: TARGET=armv7s-apple-ios DISABLE_TESTS=1 + os: osx + - env: TARGET=i386-apple-ios DISABLE_TESTS=1 + os: osx + - env: TARGET=x86_64-apple-ios DISABLE_TESTS=1 + os: osx + + # Linux + - env: TARGET=aarch64-unknown-linux-gnu + - env: TARGET=arm-unknown-linux-gnueabi + - env: TARGET=armv7-unknown-linux-gnueabihf + - env: TARGET=i686-unknown-linux-gnu + - env: TARGET=i686-unknown-linux-musl + - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 + - env: TARGET=mipsel-unknown-linux-gnu + - env: TARGET=powerpc-unknown-linux-gnu + - env: TARGET=powerpc64-unknown-linux-gnu + - env: TARGET=powerpc64le-unknown-linux-gnu + - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1 + - env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-musl + + # OSX + - env: TARGET=i686-apple-darwin + os: osx + - env: TARGET=x86_64-apple-darwin + os: osx + + # *BSD + - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1 + - env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1 + - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1 + + # Windows + - env: TARGET=x86_64-pc-windows-gnu + + # Bare metal + # These targets don't support std and as such are likely not suitable for + # most crates. + # - env: TARGET=thumbv6m-none-eabi + # - env: TARGET=thumbv7em-none-eabi + # - env: TARGET=thumbv7em-none-eabihf + # - env: TARGET=thumbv7m-none-eabi + + # Testing other channels + - env: TARGET=x86_64-unknown-linux-gnu + rust: nightly + - env: TARGET=x86_64-apple-darwin + os: osx + rust: nightly + +before_install: + - set -e + - rustup self update + +install: + - sh ci/install.sh + - source ~/.cargo/env || true + +script: + - bash ci/script.sh + +after_script: set +e + +before_deploy: + - sh ci/before_deploy.sh + +deploy: + # TODO update `api_key.secure` + # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new + # - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789 + # - Paste the output down here + api_key: + secure: "rG0L7YpKM2a2p3csThuONY8vEUjWVbw+NtADZOznPO3ZK1RLcIWxS6KV4D2kU5AWGREZmwrXlXdl9od38Dw92O7U2tb8GuAJcGz3FAGnQkDnvCpOGBx4uzNK2ARRS+euWzJd51pjFQMy9cJb7P6gpLnUf+oFu+JUQ5swTdqZXf9SkmQrboTn0XQetv9yQvtRBSDr8+UTucw2TJdU1+KjzH6dd76WCpHABum1Aveo0eFi/VkI0Vzw7rCSNBwrUiQHX0SNBY2Dm18+gkiQmdMFst9sO/YhF4FPw0ZcUweOzOF1ZWp0Bnnxi7pCEb5ELZKFi3COzAjI3jfJr9bHNmfsrZoXhleeRo+juh854oPi2+qwrWIWrL8jKwYGgFvNWKIj0/sfYvOr0DEZjbpD1siJe5E57CPtN0MAdZAvG3s4W60v75nAGChMWjIReKotfJkGSh4TmjqSyEdiJ5gLQjAGFdNYSwryea0MgdvpGa5qXyoExDuQoYern9HFgYBi8M3rfs/coOuA5LO/52FJC+1JqhNHIGCAarRgc10fcsxqcBHUxZ5mUYozHaJaV9jp7+WHqUriEhSiLOBEJpZjPwC92n4AKXe3yisbixfrQ40N4KzzUp0kamngcU7ZkPDT02aGGxwOuiU6tdcab9v2eGw9DmSedhDR8cDPd3jBuscvlAE=" + file_glob: true + file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.* + on: + # TODO Here you can pick which targets will generate binary releases + # In this example, there are some targets that are tested using the stable + # and nightly channels. This condition makes sure there is only one release + # for such targets and that's generated using the stable channel + condition: $TRAVIS_RUST_VERSION = stable + tags: true + provider: releases + skip_cleanup: true + +cache: cargo +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +branches: + only: + # release tags + - /^v\d+\.\d+\.\d+.*$/ + - master + +notifications: + email: + on_success: never diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..445b90d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "reaper" +version = "2.0.0" +authors = ["Jordan Doyle "] +repository = "https://github.com/w4/reaper.git" +homepage = "https://github.com/w4/reaper" +license = "MIT" +readme = "README.md" +description = "League of Legends username availablity checker." + +[dependencies] +ratelimit = "0.4.2" +reqwest = "0.8.1" +clap = "2.27.1" +lazy_static = "0.2" +fern = "0.4.3" +log = "0.3.8" +chrono = "0.4" +regex = "0.2.2" diff --git a/README.md b/README.md index e363a55..4009ee4 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,42 @@ # reaper -[![License](https://poser.pugx.org/laravel/framework/license.svg)](http://github.com/jordandoyle/reaper) +[![License](https://img.shields.io/github/license/w4/reaper.svg?style=flat-square)](http://github.com/jordandoyle/reaper) -[League of Legends](http://leagueoflegends.com) mass summoner name checker. Supply a region and a list and the script will check the list for available summoner names. Common uses are finding quick variations of your name or finding rare (or "OG") names for selling. An API Key is required to do use this script, they are available for free from [Riot Games](https://developer.riotgames.com/), the API key is set in **reaper.js**. +[League of Legends](http://leagueoflegends.com) mass summoner name checker. Supply a region and a list +and the application will check the list for available summoner names. Common uses are finding quick +variations of your name or finding rare (or "OG") names for selling. An API Key is required to do use +this script, they are available for free from [Riot Games](https://developer.riotgames.com/). -You can find a list of the servers you can query from on [Riot's website](https://developer.riotgames.com/regional-endpoints.html). +You can find a list of the servers you can query from on +[Riot's website](https://developer.riotgames.com/regional-endpoints.html). Examples of inputs for +SERVER: `euw1`, `na1`, `pbe1`. -The syntax of reaper is very simple: + Reaper 0.1.0 + Jordan Doyle + Scans over a given list for available usernames on League of Legends - node reaper.js [server (na1/euw1/la1/etc)] [username file] (output file) + USAGE: + reaper [FLAGS] [OPTIONS] + + FLAGS: + -h, --help Prints help information + -V, --version Prints version information + -v, --verbose Increases logging verbosity each use up to 3 times + + OPTIONS: + -o, --output Sets an output file to write available usernames to + + ARGS: + Sets the server to search for usernames on + Sets the input file to use + Sets the API key to use For example: - node reaper.js euw1 username_list.txt output.txt + ./reaper euw1 username_list.txt my-api-key -o output.txt + +Will check the list `username_list.txt` for available summoner names on Europe West using API key `my-api-key` and +outputs what it finds to output.txt -Will check the list username_list.txt for available summoner names on Europe West and output what it finds to output.txt +Builds are available under releases or you can build it from source by pulling down the code and running +`cargo build --release`. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..a718c2a --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,93 @@ +# Based on the "trust" template v0.1.1 +# https://github.com/japaric/trust/tree/v0.1.1 + +environment: + global: + # TODO This is the Rust channel that build jobs will use by default but can be + # overridden on a case by case basis down below + RUST_VERSION: stable + + # TODO Update this to match the name of your project. + CRATE_NAME: reaper + + # TODO These are all the build jobs. Adjust as necessary. Comment out what you + # don't need + matrix: + # MinGW + - TARGET: i686-pc-windows-gnu + - TARGET: x86_64-pc-windows-gnu + + # MSVC + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc + + # Testing other channels + - TARGET: x86_64-pc-windows-gnu + RUST_VERSION: nightly + - TARGET: x86_64-pc-windows-msvc + RUST_VERSION: nightly + +install: + - ps: >- + If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { + $Env:PATH += ';C:\msys64\mingw64\bin' + } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { + $Env:PATH += ';C:\msys64\mingw32\bin' + } + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -Vv + - cargo -V + +# TODO This is the "test phase", tweak it as you see fit +test_script: + # we don't run the "test phase" when doing deploys + - if [%APPVEYOR_REPO_TAG%]==[false] ( + cargo build --target %TARGET% && + cargo build --target %TARGET% --release && + cargo test --target %TARGET% && + cargo test --target %TARGET% --release && + cargo run --target %TARGET% && + cargo run --target %TARGET% --release + ) + +before_deploy: + # TODO Update this to build the artifacts that matter to you + - cargo rustc --target %TARGET% --release --bin reaper -- -C lto + - ps: ci\before_deploy.ps1 + +deploy: + artifact: /.*\.zip/ + # TODO update `auth_token.secure` + # - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new + # - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt + # - Paste the output down here + auth_token: + secure: ZVn4BWuEyloI1h+dDXJ4fjuJBHqMAouGCOrODmLdWcPeLHhy8ovJ9Rac15FrVBhp + description: '' + on: + # TODO Here you can pick which targets will generate binary releases + # In this example, there are some targets that are tested using the stable + # and nightly channels. This condition makes sure there is only one release + # for such targets and that's generated using the stable channel + RUST_VERSION: stable + appveyor_repo_tag: true + provider: GitHub + +cache: + - C:\Users\appveyor\.cargo\registry + - target + +branches: + only: + # Release tags + - /^v\d+\.\d+\.\d+.*$/ + - master + +notifications: + - provider: Email + on_build_success: false + +# Building is done in the test phase, so we disable Appveyor's build phase. +build: false diff --git a/ci/before_deploy.ps1 b/ci/before_deploy.ps1 new file mode 100644 index 0000000..382a055 --- /dev/null +++ b/ci/before_deploy.ps1 @@ -0,0 +1,23 @@ +# This script takes care of packaging the build artifacts that will go in the +# release zipfile + +$SRC_DIR = $PWD.Path +$STAGE = [System.Guid]::NewGuid().ToString() + +Set-Location $ENV:Temp +New-Item -Type Directory -Name $STAGE +Set-Location $STAGE + +$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip" + +# TODO Update this to package the right artifacts +Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\reaper.exe" '.\' + +7z a "$ZIP" * + +Push-AppveyorArtifact "$ZIP" + +Remove-Item *.* -Force +Set-Location .. +Remove-Item $STAGE +Set-Location $SRC_DIR diff --git a/ci/before_deploy.sh b/ci/before_deploy.sh new file mode 100644 index 0000000..94555ac --- /dev/null +++ b/ci/before_deploy.sh @@ -0,0 +1,33 @@ +# This script takes care of building your crate and packaging it for release + +set -ex + +main() { + local src=$(pwd) \ + stage= + + case $TRAVIS_OS_NAME in + linux) + stage=$(mktemp -d) + ;; + osx) + stage=$(mktemp -d -t tmp) + ;; + esac + + test -f Cargo.lock || cargo generate-lockfile + + # TODO Update this to build the artifacts that matter to you + cross rustc --bin reaper --target $TARGET --release -- -C lto + + # TODO Update this to package the right artifacts + cp target/$TARGET/release/reaper $stage/ + + cd $stage + tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz * + cd $src + + rm -rf $stage +} + +main diff --git a/ci/install.sh b/ci/install.sh new file mode 100644 index 0000000..80e18e4 --- /dev/null +++ b/ci/install.sh @@ -0,0 +1,47 @@ +set -ex + +main() { + local target= + if [ $TRAVIS_OS_NAME = linux ]; then + target=x86_64-unknown-linux-musl + sort=sort + else + target=x86_64-apple-darwin + sort=gsort # for `sort --sort-version`, from brew's coreutils. + fi + + # Builds for iOS are done on OSX, but require the specific target to be + # installed. + case $TARGET in + aarch64-apple-ios) + rustup target install aarch64-apple-ios + ;; + armv7-apple-ios) + rustup target install armv7-apple-ios + ;; + armv7s-apple-ios) + rustup target install armv7s-apple-ios + ;; + i386-apple-ios) + rustup target install i386-apple-ios + ;; + x86_64-apple-ios) + rustup target install x86_64-apple-ios + ;; + esac + + # This fetches latest stable release + local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ + | cut -d/ -f3 \ + | grep -E '^v[0.1.0-9.]+$' \ + | $sort --version-sort \ + | tail -n1) + curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- \ + --force \ + --git japaric/cross \ + --tag $tag \ + --target $target +} + +main diff --git a/ci/script.sh b/ci/script.sh new file mode 100644 index 0000000..ddd7f93 --- /dev/null +++ b/ci/script.sh @@ -0,0 +1,24 @@ +# This script takes care of testing your crate + +set -ex + +# TODO This is the "test phase", tweak it as you see fit +main() { + cross build --target $TARGET + cross build --target $TARGET --release + + if [ ! -z $DISABLE_TESTS ]; then + return + fi + + cross test --target $TARGET + cross test --target $TARGET --release + + cross run --target $TARGET + cross run --target $TARGET --release +} + +# we don't run the "test phase" when doing deploys +if [ -z $TRAVIS_TAG ]; then + main +fi diff --git a/common.js b/common.js deleted file mode 100644 index 756bdad..0000000 --- a/common.js +++ /dev/null @@ -1,12 +0,0 @@ -const colors = require('colors'); - -console.error = (msg) => console.log("[".white + "!".red + "] ".white + msg.white); -console.info = (msg) => console.log("[".white + "-".green + "] ".white + msg.white); -console.warn = (msg) => console.log("[".white + "~".blue + "] ".white + msg.white); - -exports.shuffle = (array) => { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } -}; diff --git a/package.json b/package.json deleted file mode 100644 index 8594b15..0000000 --- a/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "reaper", - "description": "League of Legends available name scraper", - "version": "1.0.2", - "author": "Jordan Doyle ", - "main": "reaper.js", - "repository": { - "type": "git", - "url": "git://github.com/JordanDoyle/reaper.git" - }, - "bugs": { - "url": "https://github.com/JordanDoyle/reaper/issues" - }, - "dependencies": { - "chunk": "~0.0.2", - "colors": "~1.1.2", - "limiter": "~1.0.5" - }, - "license": "MIT" -} \ No newline at end of file diff --git a/reaper.js b/reaper.js deleted file mode 100644 index ecb2e2b..0000000 --- a/reaper.js +++ /dev/null @@ -1,46 +0,0 @@ -"use strict"; - -const common = require('./common'); -const chunk = require('chunk'); -const fs = require('fs'); -const https = require('https'); -const RateLimiter = require('limiter').RateLimiter; - -const args = process.argv.slice(2); - -if(args.length < 2 || args.length > 3) { - console.error("Invalid syntax. Valid syntax: " + process.argv[0] + " " + process.argv[1] + " [server] [username input] (username output)"); -} - -const apiKey = ""; - -const server = args[0]; -const input = args[1]; -const output = args[2]; - -const limiter = new RateLimiter(1, 'second'); - -const names = fs.readFileSync(input).toString().split('\n'); - -// shuffle the list of names passed in -common.shuffle(names); - -for (let name of names) { - name = name.replace(/[-]/g, ' ').replace(/[\r\n'.]/g, '').trim(); - - if(name.length < 3) - continue; - - limiter.removeTokens(1, () => { - // make a secure request to the specified server - https.get(`https://${server}.api.riotgames.com/lol/summoner/v3/summoners/by-name/${name}?api_key=${apiKey}`, (res) => { - // riot returns a 404 if none of the names are registered - if(res.statusCode === 404) { - console.info(name.replace(/[-]/g, ' ').replace(/[\r\n'.]/g, '') + " is available!"); - - if(output !== undefined) - fs.appendFile(output, name + '\n', () => null); - } - }); - }); -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1e80071 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,175 @@ +extern crate chrono; +#[macro_use] +extern crate clap; +extern crate fern; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +extern crate ratelimit; +extern crate regex; +extern crate reqwest; + +use std::time::Duration; +use std::error::Error; +use std::io::{BufRead, BufReader, Write}; +use std::fs::{File, OpenOptions}; +use std::path::Path; +use clap::{App, Arg}; +use reqwest::StatusCode; +use regex::Regex; + +lazy_static! { + static ref CLIENT: reqwest::Client = reqwest::Client::new(); + static ref USERNAME_REGEX: Regex = Regex::new(r"^[0-9\p{L} _\\.]{3,16}$").unwrap(); +} + +fn setup_logger(verbosity: u64) -> Result<(), fern::InitError> { + fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "{} [{}] [{}] {}", + chrono::Local::now().format("%e %b %Y %H:%M:%S%.3f"), + record.target(), + record.level(), + message + )) + }) + .level(match verbosity { + 0 | 1 => log::LogLevelFilter::Info, + 2 => log::LogLevelFilter::Debug, + _ => log::LogLevelFilter::Trace, + }) + .level_for("reaper", match verbosity { + 0 => log::LogLevelFilter::Info, + 1 => log::LogLevelFilter::Debug, + _ => log::LogLevelFilter::Trace, + }) + .chain(std::io::stdout()) + .apply()?; + + Ok(()) +} + +fn argparse<'a, 'b>() -> clap::App<'a, 'b> { + App::new("Reaper") + .version(crate_version!()) + .author("Jordan Doyle ") + .about("Scans over a given list for available usernames on League of Legends") + .arg(Arg::with_name("SERVER") + .help("Sets the server to search for usernames on") + .required(true) + .index(1)) + .arg(Arg::with_name("INPUT") + .help("Sets the input file to use") + .required(true) + .index(2)) + .arg(Arg::with_name("API KEY") + .help("Sets the API key to use") + .required(true) + .index(3)) + .arg(Arg::with_name("output") + .short("o") + .long("output") + .value_name("FILE") + .help("Sets an output file to write available usernames to") + .takes_value(true)) + .arg(Arg::with_name("verbose") + .short("v") + .long("verbose") + .multiple(true) + .help("Increases logging verbosity each use up to 3 times")) +} + +fn main() { + let args = argparse().get_matches(); + + setup_logger(args.occurrences_of("verbose")).expect("Failed to initialize logging."); + + info!("Reaper booting up."); + + // all our inputs below are required fields so we can unwrap them without any worries + let server = args.value_of("SERVER").unwrap(); + let input = Path::new(args.value_of("INPUT").unwrap()); + let api_key = args.value_of("API KEY").unwrap(); + + assert!(input.exists(), "Input file doesn't exist."); + + let output = args.value_of("output"); + + // output is an optional field so we check if it has a value and if it does we build a + // new File instance and create a new Option with it + let output_file = if output.is_some() { + match OpenOptions::new() + .create(true) + .append(true) + .open(output.unwrap()) + { + Ok(file) => Some(file), + Err(e) => { + error!("Couldn't open handle to output file. {}", e); + panic!() + } + } + } else { + None + }; + + debug!("Finished parsing arguments"); + + let mut ratelimit = ratelimit::Builder::new() + .capacity(1) // number of tokens the bucket will hold + .quantum(1) // add one token per interval + .interval(Duration::new(1, 0)) // add quantum tokens every 1 second + .build(); + + for line in BufReader::new(File::open(input).unwrap()).lines() { + let username = &line.unwrap(); + + if !USERNAME_REGEX.is_match(username) { + error!( + "The username \"{}\" isn't a valid username, skipping.", + username + ); + continue; + } + + debug!("Checking if \"{}\" is available", username); + + match send_request(server, api_key, username) { + Ok(_) => { + info!("{} is available!", username); + + if let Some(ref mut file) = output_file.as_ref() { + writeln!(file, "{}", username).unwrap(); + } + } + Err(e) => info!("{} is not available ({})", username, e), + } + + ratelimit.wait(); + } +} + +fn send_request(server: &str, api_key: &str, username: &str) -> Result<(), Box> { + let resp = CLIENT + .get(&format!( + "https://{}.api.riotgames.com/lol/summoner/v3/summoners/by-name/{}?api_key={}", + server, + username, + api_key + )) + .send()?; + + debug!("{:?}", resp); + + if !resp.status().is_success() { + if resp.status().eq(&StatusCode::NotFound) { + Ok(()) + } else { + Err(Box::from("Bad response from Riot API")) + } + } else { + Err(Box::from("Username is taken")) + } +} -- libgit2 1.7.2