From 1b82b0a7776aee31f553fb588be4fa9691592248 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Mon, 26 Apr 2021 15:42:39 -0700 Subject: major: :star: --- .dockerignore | 1 + .editorconfig | 9 +++ .envrc | 1 + .gitignore | 11 ++++ .license_template | 2 + .mergify.yml | 8 +++ Cargo.toml | 22 +++++++ Dockerfile | 18 ++++++ Procfile | 1 + Rocket.toml | 2 + contributing.md | 6 ++ default.nix | 19 ++++++ maintainers | 1 + nix/rust.nix | 9 +++ nix/sources.json | 50 +++++++++++++++ nix/sources.nix | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 30 +++++++++ rust-toolchain | 2 + rust-toolchain.toml | 2 + rustfmt.toml | 29 +++++++++ senpy-api.nix | 17 +++++ shell.nix | 9 +++ src/constants.rs | 8 +++ src/main.rs | 27 ++++++++ src/routes.rs | 78 +++++++++++++++++++++++ src/structures.rs | 28 +++++++++ src/utils.rs | 52 ++++++++++++++++ 27 files changed, 616 insertions(+) create mode 100644 .dockerignore create mode 100644 .editorconfig create mode 100644 .envrc create mode 100644 .license_template create mode 100644 .mergify.yml create mode 100644 Cargo.toml create mode 100644 Dockerfile create mode 100644 Procfile create mode 100644 Rocket.toml create mode 100644 contributing.md create mode 100644 default.nix create mode 100644 maintainers create mode 100644 nix/rust.nix create mode 100644 nix/sources.json create mode 100644 nix/sources.nix create mode 100644 readme.md create mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml create mode 100644 rustfmt.toml create mode 100644 senpy-api.nix create mode 100644 shell.nix create mode 100644 src/constants.rs create mode 100644 src/main.rs create mode 100644 src/routes.rs create mode 100644 src/structures.rs create mode 100644 src/utils.rs diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +/target/ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..051d09d --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +eval "$(lorri direnv)" diff --git a/.gitignore b/.gitignore index 088ba6b..683610a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,14 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +# nix +result* + +# ide +/.idea/ +/senpy-api.iml + +# development +.env +/shell-dev.nix diff --git a/.license_template b/.license_template new file mode 100644 index 0000000..f8ef223 --- /dev/null +++ b/.license_template @@ -0,0 +1,2 @@ +// Copyleft {20\d{2}(-20\d{2})?} The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 0000000..e8e3205 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,8 @@ +pull_request_rules: + - name: Automatic merge when required reviews are approved + conditions: + - base=develop + - "#approved-reviews-by>=2" + actions: + merge: + method: merge diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..25c3869 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "senpy-api" +version = "0.1.0" +authors = ["Fuwn "] +edition = "2018" +#description = "" +readme = "README.md" +homepage = "http://github.com/senpy-club/api" +repository = "http://github.com/senpy-club/api" +license = "GPL-3.0-only" +keywords = ["rust", "anime", "senpy"] +publish = false + +[dependencies] +rocket = { version = "0.5.0-dev", git = "https://github.com/SergioBenitez/Rocket.git" } +rocket_contrib = { version = "0.5.0-dev", git = "https://github.com/SergioBenitez/Rocket.git" } +reqwest = { version = "0.11.3", features = ["json"] } +tokio = { version = "1.5.0", features = ["full"] } +serde = "1.0.125" +serde_derive = "1.0.125" +rand = "0.8.3" +dotenv = "0.15.0" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d7e3b91 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# # NOTICE +# This Dockerfile is *probably* not stable as of 2021. 04. 26. +# +# Can you use it? Yes, but you probably shouldn't. + +FROM rustlang/rust:nightly-slim AS build + +WORKDIR /src/senpy-api + +COPY . . + +RUN cargo build --release + +FROM ubuntu:18.04 + +COPY --from=build /src/senpy-api/target/release/senpy-api /usr/local/bin/senpy-api + +CMD ["/usr/local/bin/senpy-api"] diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..cb5ceb6 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: ROCKET_PORT=$PORT ROCKET_KEEP_ALIVE=0 ./target/release/senpy-api diff --git a/Rocket.toml b/Rocket.toml new file mode 100644 index 0000000..d53c0a4 --- /dev/null +++ b/Rocket.toml @@ -0,0 +1,2 @@ +[release] +port = 8084 diff --git a/contributing.md b/contributing.md new file mode 100644 index 0000000..b4aee98 --- /dev/null +++ b/contributing.md @@ -0,0 +1,6 @@ +# contribution guidelines +this document isn't very well detailed at the moment... + +## guidelines +1. at the moment, there is no github action in place to check if your pull request will compile, + please ensure that your changes **do** in-fact compile before submitting your pull request (s). diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..4f4ca20 --- /dev/null +++ b/default.nix @@ -0,0 +1,19 @@ +{ system ? builtins.currentSystem }: + +let + sources = import ./nix/sources.nix; + pkgs = import sources.nixpkgs { }; + senpy-api = import ./senpy-api.nix { inherit sources pkgs; }; + + name = "senpy-club/api"; + tag = "latest"; +in pkgs.dockerTools.buildLayeredImage { + inherit name tag; + contents = [ senpy-api ]; + + config = { + Cmd = [ "/bin/senpy-api" ]; + Env = [ ]; + WorkingDir = "/"; + }; +} diff --git a/maintainers b/maintainers new file mode 100644 index 0000000..6fad053 --- /dev/null +++ b/maintainers @@ -0,0 +1 @@ +Fuwn (@fuwn) diff --git a/nix/rust.nix b/nix/rust.nix new file mode 100644 index 0000000..77c9190 --- /dev/null +++ b/nix/rust.nix @@ -0,0 +1,9 @@ +{ sources ? import ./sources.nix }: + +let + pkgs = import sources.nixpkgs { overlays = [ (import sources.nixpkgs-mozilla) ]; }; + channel = "nightly"; + date = "2021-04-24"; + targets = [ ]; + chan = pkgs.rustChannelOfTargets channel date targets; +in chan diff --git a/nix/sources.json b/nix/sources.json new file mode 100644 index 0000000..33453bf --- /dev/null +++ b/nix/sources.json @@ -0,0 +1,50 @@ +{ + "naersk": { + "branch": "master", + "description": "Build rust crates in Nix. No configuration, no code generation, no IFD. Sandbox friendly.", + "homepage": "", + "owner": "nmattia", + "repo": "naersk", + "rev": "32e3ba39d9d83098b13720a4384bdda191dd0445", + "sha256": "0yxqggmj4c65nzmgjmwxii9ibxmxw9w87pbqpgmnyf5rpyp79nv7", + "type": "tarball", + "url": "https://github.com/nmattia/naersk/archive/32e3ba39d9d83098b13720a4384bdda191dd0445.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "niv": { + "branch": "master", + "description": "Easy dependency management for Nix projects", + "homepage": "https://github.com/nmattia/niv", + "owner": "nmattia", + "repo": "niv", + "rev": "af958e8057f345ee1aca714c1247ef3ba1c15f5e", + "sha256": "1qjavxabbrsh73yck5dcq8jggvh3r2jkbr6b5nlz5d9yrqm9255n", + "type": "tarball", + "url": "https://github.com/nmattia/niv/archive/af958e8057f345ee1aca714c1247ef3ba1c15f5e.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs": { + "branch": "release-20.03", + "description": "Nix Packages collection", + "homepage": "", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6d1a044fc9ff3cc96fca5fa3ba9c158522bbf2a5", + "sha256": "07a3nyrj3pwl017ig0rbn5rbmbf14gl3vqggvkyrdby01726p5fg", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/6d1a044fc9ff3cc96fca5fa3ba9c158522bbf2a5.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + }, + "nixpkgs-mozilla": { + "branch": "master", + "description": "mozilla related nixpkgs (extends nixos/nixpkgs repo)", + "homepage": "", + "owner": "mozilla", + "repo": "nixpkgs-mozilla", + "rev": "8c007b60731c07dd7a052cce508de3bb1ae849b4", + "sha256": "1zybp62zz0h077zm2zmqs2wcg3whg6jqaah9hcl1gv4x8af4zhs6", + "type": "tarball", + "url": "https://github.com/mozilla/nixpkgs-mozilla/archive/8c007b60731c07dd7a052cce508de3bb1ae849b4.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/nix/sources.nix b/nix/sources.nix new file mode 100644 index 0000000..1938409 --- /dev/null +++ b/nix/sources.nix @@ -0,0 +1,174 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + if spec ? ref then spec.ref else + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + in + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else {}; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..81fe664 --- /dev/null +++ b/readme.md @@ -0,0 +1,30 @@ +

+

senpy-api

+

+ +

+ +discord + + +license + +

+ +## notice +nix integration is currently broken. until [rocket](https://crates.io/crates/rocket) officially +releases version `0.5.0`, it will stay broken. + +## nix +- build: `nix-build senpy-api.nix` +- docker: `nix-build default.nix` + +## usage +- run (dev): `ROCKET_ENV=dev cargo run` +- build (prod): `ROCKET_ENV=prod cargo build --release` + +## contributing +please reference the [contribution guidelines](./contributing.md) of this repository. + +### license +[gnu general public license v3.0](https://github.com/senpy-club/api/blob/main/license) diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..011b8ea --- /dev/null +++ b/rust-toolchain @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2021-04-24" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..011b8ea --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2021-04-24" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..de1e0ce --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,29 @@ +condense_wildcard_suffixes = true +edition = "2018" +enum_discrim_align_threshold = 20 +error_on_line_overflow = true +error_on_unformatted = true +fn_single_line = true +force_multiline_blocks = true +format_code_in_doc_comments = true +format_macro_matchers = true +format_strings = true +imports_layout = "HorizontalVertical" +license_template_path = ".license_template" +match_arm_blocks = false +imports_granularity = "Crate" +newline_style = "Unix" +normalize_comments = true +normalize_doc_attributes = true +reorder_impl_items = true +group_imports = "StdExternalCrate" +reorder_modules = true +report_fixme = "Always" +report_todo = "Always" +struct_field_align_threshold = 20 +struct_lit_single_line = false +tab_spaces = 2 +use_field_init_shorthand = true +use_try_shorthand = true +where_single_line = true +wrap_comments = true diff --git a/senpy-api.nix b/senpy-api.nix new file mode 100644 index 0000000..a08a9b2 --- /dev/null +++ b/senpy-api.nix @@ -0,0 +1,17 @@ +{ sources ? import ./nix/sources.nix, pkgs ? import sources.nixpkgs { } }: + +let + rust = import ./nix/rust.nix { inherit sources; }; + + naersk = pkgs.callPackage sources.naersk { + rustc = rust; + cargo = rust; + }; + + src = builtins.filterSource + (path: type: type != "directory" || builtins.baseNameOf path != "target") + ./.; +in naersk.buildPackage { + inherit src; + remapPathPrefix = true; +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..2fbdb27 --- /dev/null +++ b/shell.nix @@ -0,0 +1,9 @@ +let + sources = import ./nix/sources.nix; + rust = import ./nix/rust.nix { inherit sources; }; + pkgs = import sources.nixpkgs { }; +in pkgs.mkShell { + buildInputs = with pkgs; [ rust ]; + + # GITHUB_TOKEN = ""; +} diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..adbde90 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,8 @@ +// Copyleft 2021-2021 The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only + +pub const GITHUB_USER_CONTENT: &str = + "https://raw.githubusercontent.com/laynH/Anime-Girls-Holding-Programming-Books/master/"; +pub const GITHUB_API_ENDPOINT: &str = "https://api.github.com/repos/laynH/Anime-Girls-Holding-Progr\ +amming-Books/git/trees/master?recursive=1"; +pub const USER_AGENT: &str = env!("CARGO_PKG_NAME"); diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..35af208 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,27 @@ +// Copyleft 2021-2021 The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only + +#![feature(proc_macro_hygiene, decl_macro, type_ascription)] + +#[macro_use] +extern crate rocket; + +pub mod constants; +pub mod routes; +pub mod structures; +pub mod utils; + +#[launch] +fn rocket() -> _ { + dotenv::dotenv().ok(); + + rocket::build().mount("/", routes![routes::index]).mount( + "/api/v1", + routes![ + routes::github, + routes::languages, + routes::language, + routes::random + ], + ) +} diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..e492404 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,78 @@ +// Copyleft 2021-2021 The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only + +use rand::{thread_rng, Rng}; +use rocket_contrib::json::Json; + +use crate::{ + structures::{GitHubAPIResponse, SenpyRandom}, + utils::{filter_images_by_language, filter_languages, github_api}, +}; + +#[get("/")] +pub fn index() -> &'static str { + r#"# senpy-api +## routes +if a language requires a parameter, it will be notated like . +for example; if a route is notated as "/api/v1/route?", you can +access that route via the url +"http://this.domain/api/v1/route?parameter=something" + +- / + - /: index page (you are here) + +- /api/v1 + - /github: github api mirror + - /languages: a list of all languages that appear in _the_ repository + - /language?: get a list of all images that pertain to the language "" + +## notes +### rate-limit (s) +there aren't any rate-limits or whatnot on api usage but don't abuse it, it only takes one bad +apple to spoil the lot. + +### contributing +if you'd like to support the project in anyway, check out the repository! +https://github.com/senpy-club/api + +### supporting +if you would like to support my development ventures, visit my github profile here :3 +https://github.com/fuwn + +### license +gnu general public license v3.0 (gpl-3.0-only) +https://github.com/senpy-club/api/blob/main/LICENSE"# +} + +#[get("/github")] +pub async fn github() -> Json { Json(github_api().await.unwrap()) } + +#[get("/languages")] +pub async fn languages() -> Json> { Json(filter_languages().await) } + +#[get("/language?")] +pub async fn language(lang: Option) -> Json> { + // lang.map(async |lang| Json(filter_images_by_language(lang).await)) + // .unwrap_or_else(|| Json(vec!["invalid language or no language + // specified".to_string()])); + + return if lang.is_none() { + Json(vec!["invalid language or no language specified".to_string()]) + } else { + Json(filter_images_by_language(lang.unwrap()).await) + }; +} + +#[get("/random")] +pub async fn random() -> Json { + let filtered_languages = filter_languages().await; + let random_language = + &filtered_languages[thread_rng().gen_range(0..filtered_languages.len() - 1)]; + let filtered_images = filter_images_by_language(random_language.clone().to_owned()).await; + let random_image = &filtered_images[thread_rng().gen_range(0..filtered_images.len() - 1)]; + + Json(SenpyRandom { + language: random_language.clone().to_owned(), + image: random_image.clone().to_owned(), + }) +} diff --git a/src/structures.rs b/src/structures.rs new file mode 100644 index 0000000..2a85111 --- /dev/null +++ b/src/structures.rs @@ -0,0 +1,28 @@ +// Copyleft 2021-2021 The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only + +use serde_derive::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +pub struct GitHubAPIResponse { + pub sha: String, + pub url: String, + pub tree: Vec, + pub truncated: bool, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct GitHubAPIResponseTree { + pub path: String, + pub mode: String, + #[serde(rename = "type")] + pub _type: String, + pub sha: String, + pub url: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct SenpyRandom { + pub(crate) language: String, + pub image: String, +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..d51a813 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,52 @@ +// Copyleft 2021-2021 The Senpy Club +// SPDX-License-Identifier: GPL-3.0-only + +use crate::{ + constants::{GITHUB_API_ENDPOINT, GITHUB_USER_CONTENT, USER_AGENT}, + structures::GitHubAPIResponse, +}; + +pub async fn github_api() -> Result { + Ok( + reqwest::Client::new() + .get(GITHUB_API_ENDPOINT) + .header("User-Agent", USER_AGENT) + .header( + "Authorization", + format!("token {}", std::env::var("GITHUB_TOKEN").unwrap()), + ) + .send() + .await? + .json::() + .await?, + ) +} + +pub async fn filter_languages() -> Vec { + let mut languages = vec![]; + + for i in github_api().await.unwrap().tree { + if i._type == "tree" { + languages.push(i.path); + } + } + + languages +} + +pub async fn filter_images_by_language(language: String) -> Vec { + let mut images = vec![]; + + for i in github_api().await.unwrap().tree { + // Example: + // "Language/Image.png" would become ["Language", "Image.png"] + + // TODO: Fix this with type_ascription + let x: Vec<&str> = i.path.split("/").collect(); + if x[0] == language && i.path.contains('/') { + images.push(format!("{}{}", GITHUB_USER_CONTENT, i.path)) + } + } + + images +} -- cgit v1.2.3