aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2021-04-26 15:42:39 -0700
committerFuwn <[email protected]>2021-04-26 15:42:39 -0700
commit1b82b0a7776aee31f553fb588be4fa9691592248 (patch)
treed0a678e4a6735dfd92e92b1aab33a3447c3666ee
parentfmt: Change case (diff)
downloadapi-1b82b0a7776aee31f553fb588be4fa9691592248.tar.xz
api-1b82b0a7776aee31f553fb588be4fa9691592248.zip
major: :star:
-rw-r--r--.dockerignore1
-rw-r--r--.editorconfig9
-rw-r--r--.envrc1
-rw-r--r--.gitignore11
-rw-r--r--.license_template2
-rw-r--r--.mergify.yml8
-rw-r--r--Cargo.toml22
-rw-r--r--Dockerfile18
-rw-r--r--Procfile1
-rw-r--r--Rocket.toml2
-rw-r--r--contributing.md6
-rw-r--r--default.nix19
-rw-r--r--maintainers1
-rw-r--r--nix/rust.nix9
-rw-r--r--nix/sources.json50
-rw-r--r--nix/sources.nix174
-rw-r--r--readme.md30
-rw-r--r--rust-toolchain2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--rustfmt.toml29
-rw-r--r--senpy-api.nix17
-rw-r--r--shell.nix9
-rw-r--r--src/constants.rs8
-rw-r--r--src/main.rs27
-rw-r--r--src/routes.rs78
-rw-r--r--src/structures.rs28
-rw-r--r--src/utils.rs52
27 files changed, 616 insertions, 0 deletions
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 <[email protected]>"]
+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 <[email protected]> (@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/<owner>/<repo>/archive/<rev>.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/<owner>/<repo>/archive/<rev>.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/<owner>/<repo>/archive/<rev>.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/<owner>/<repo>/archive/<rev>.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_<type> fetches specs of type <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 = <nixpkgs> == ./.;
+ in
+ if builtins.hasAttr "nixpkgs" sources
+ then sourcesNixpkgs
+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
+ import <nixpkgs> {}
+ else
+ abort
+ ''
+ Please specify either <nixpkgs> (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 @@
+<p align="center">
+<h1>senpy-api</h1>
+</p>
+
+<p align="center">
+<a href="https://discord.com/invite/yWKgRT6" title="discord">
+<img src="https://img.shields.io/discord/246524734718738442" alt="discord">
+</a>
+<a href="./license" title="license">
+<img src="https://img.shields.io/github/license/Whirlsplash/whirl" alt="license">
+</a>
+</p>
+
+## 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 <this>.
+for example; if a route is notated as "/api/v1/route?<parameter>", 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?<lang>: get a list of all images that pertain to the language "<lang>"
+
+## 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<GitHubAPIResponse> { Json(github_api().await.unwrap()) }
+
+#[get("/languages")]
+pub async fn languages() -> Json<Vec<String>> { Json(filter_languages().await) }
+
+#[get("/language?<lang>")]
+pub async fn language(lang: Option<String>) -> Json<Vec<String>> {
+ // 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<SenpyRandom> {
+ 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<GitHubAPIResponseTree>,
+ 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<GitHubAPIResponse, reqwest::Error> {
+ 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::<GitHubAPIResponse>()
+ .await?,
+ )
+}
+
+pub async fn filter_languages() -> Vec<String> {
+ 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<String> {
+ 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
+}