diff options
| author | Fuwn <[email protected]> | 2022-03-24 02:17:31 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2022-03-24 02:17:31 -0700 |
| commit | 993ae59613d41ff25c33f814aed6415a645477dc (patch) | |
| tree | ae70cc1059a242b00996336844eb1d53e43bf466 | |
| parent | feat: cache github api (diff) | |
| download | api-worker-993ae59613d41ff25c33f814aed6415a645477dc.tar.xz api-worker-993ae59613d41ff25c33f814aed6415a645477dc.zip | |
feat(routes): support for anime boys
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/boys.rs | 35 | ||||
| -rw-r--r-- | src/index.rst | 6 | ||||
| -rw-r--r-- | src/lib.rs | 23 | ||||
| -rw-r--r-- | src/routes.rs | 22 | ||||
| -rw-r--r-- | src/structures.rs | 6 | ||||
| -rw-r--r-- | src/utils.rs | 90 |
7 files changed, 148 insertions, 36 deletions
@@ -2,7 +2,7 @@ [package] name = "api-worker" -version = "0.2.0" +version = "0.2.1" authors = ["Fuwn <[email protected]>"] edition = "2021" description = "API (as a Cloudflare Worker!)" diff --git a/src/boys.rs b/src/boys.rs new file mode 100644 index 0000000..1f94259 --- /dev/null +++ b/src/boys.rs @@ -0,0 +1,35 @@ +// This file is part of api-worker <https://github.com/senpy-club/api-worker>. +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// +// Copyright (C) 2022-2022 Fuwn <[email protected]> +// SPDX-License-Identifier: GPL-3.0-only + +use std::lazy::SyncLazy; + +pub const GITHUB_REPOSITORY: &str = + "flyingcakes85/Anime-Boys-Holding-Programming-Books"; + +pub static GITHUB_USER_CONTENT: SyncLazy<String> = SyncLazy::new(|| { + format!( + "https://raw.githubusercontent.com/{}/master/", + GITHUB_REPOSITORY + ) +}); +pub static GITHUB_API_ENDPOINT: SyncLazy<String> = SyncLazy::new(|| { + format!( + "https://api.github.com/repos/{}/git/trees/main?recursive=1", + GITHUB_REPOSITORY, + ) +}); diff --git a/src/index.rst b/src/index.rst index 2de518c..4b9ebe9 100644 --- a/src/index.rst +++ b/src/index.rst @@ -20,6 +20,12 @@ For example; if a route is notated as "/v2/route/:parameter", you can access tha - /random: A random image from the https://github.com/cat-milk/Anime-Girls-Holding-Programming-Books repository - /me: For future implementation. At the moment; only contains the caller's IP. +- /v2/boys + - /github: GitHub API mirror for the https://github.com/flyingcakes85/Anime-Boys-Holding-Programming-Books repository + - /languages: A list of all languages that appear in the https://github.com/flyingcakes85/Anime-Boys-Holding-Programming-Books repository + - /language/:language: A list of all images that are labeled under the language, ":language", in the https://github.com/flyingcakes85/Anime-Boys-Holding-Programming-Books repository + - /random: A random image from the https://github.com/flyingcakes85/Anime-Boys-Holding-Programming-Books repository + Notes ----- @@ -31,6 +31,7 @@ #[global_allocator] static ALLOC: wee_alloc::WeeAlloc<'_> = wee_alloc::WeeAlloc::INIT; +mod boys; mod constants; mod routes; mod structures; @@ -39,6 +40,8 @@ mod utils; use serde_json::json; use worker::Response; +use crate::structures::Type; + /// # Errors /// if `worker::Router` errors #[worker::event(fetch)] @@ -52,18 +55,30 @@ pub async fn main( worker::Router::new() .get("/", |_, _| routes::index()) .get("/v2", |_, _| routes::index()) - .get_async("/v2/github", |_, _| async move { routes::github().await }) + .get_async("/v2/github", |_, _| async move { routes::github(Type::Girls).await }) + .get_async("/v2/boys/github", |_, _| async move { routes::github(Type::Boys).await }) .get_async( "/v2/languages", - |_, _| async move { routes::languages().await }, + |_, _| async move { routes::languages(Type::Girls).await }, + ) + .get_async( + "/v2/boys/languages", + |_, _| async move { routes::languages(Type::Boys).await }, ) .get_async("/v2/language/:language", |_, ctx| { async move { - routes::language(ctx.param("language").unwrap_or(&"null".to_string())) + routes::language(ctx.param("language").unwrap_or(&"null".to_string()), Type::Girls) + .await + } + }) + .get_async("/v2/boys/language/:language", |_, ctx| { + async move { + routes::language(ctx.param("language").unwrap_or(&"null".to_string()), Type::Boys) .await } }) - .get_async("/v2/random", |_, _| async move { routes::random().await }) + .get_async("/v2/random", |_, _| async move { routes::random(Type::Girls).await }) + .get_async("/v2/boys/random", |_, _| async move { routes::random(Type::Boys).await }) .get("/v2/version", |_, _| { Response::from_json(&json!({ "crate_version": env!("CARGO_PKG_VERSION"), diff --git a/src/routes.rs b/src/routes.rs index 9e4767a..bfd2292 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -20,7 +20,7 @@ use rand::{thread_rng, Rng}; use worker::{Response, Result}; use crate::{ - structures::SenpyRandom, + structures::{SenpyRandom, Type}, utils::{cors, filter_images_by_language, filter_languages, github_api}, }; @@ -28,24 +28,26 @@ pub fn index() -> Result<Response> { Response::ok(&*crate::constants::INDEX)?.with_cors(&cors()) } -pub async fn github() -> Result<Response> { - Response::from_json(&github_api().await.unwrap())?.with_cors(&cors()) +pub async fn github(repository: Type) -> Result<Response> { + Response::from_json(&github_api(repository).await.unwrap())? + .with_cors(&cors()) } -pub async fn languages() -> Result<Response> { - Response::from_json(&filter_languages().await)?.with_cors(&cors()) +pub async fn languages(repository: Type) -> Result<Response> { + Response::from_json(&filter_languages(repository).await)?.with_cors(&cors()) } -pub async fn language(language: &str) -> Result<Response> { - Response::from_json(&filter_images_by_language(language).await)? +pub async fn language(language: &str, repository: Type) -> Result<Response> { + Response::from_json(&filter_images_by_language(language, repository).await)? .with_cors(&cors()) } -pub async fn random() -> Result<Response> { - let filtered_languages = filter_languages().await; +pub async fn random(repository: Type) -> Result<Response> { + let filtered_languages = filter_languages(repository.clone()).await; let random_language = &filtered_languages [thread_rng().gen_range(0..filtered_languages.len() - 1)]; - let filtered_images = filter_images_by_language(random_language).await; + let filtered_images = + filter_images_by_language(random_language, repository).await; let random_image = if filtered_images.len() == 1 { &filtered_images[0] } else { diff --git a/src/structures.rs b/src/structures.rs index 4c59d51..fca356f 100644 --- a/src/structures.rs +++ b/src/structures.rs @@ -20,6 +20,12 @@ use serde_derive::{Deserialize, Serialize}; +#[derive(PartialEq, Clone)] +pub enum Type { + Girls, + Boys, +} + #[derive(Serialize, Deserialize, Clone)] pub struct GitHubAPIResponse { pub sha: String, diff --git a/src/utils.rs b/src/utils.rs index 333a1c0..c42c15c 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,25 +20,52 @@ use std::{lazy::SyncLazy, sync::Mutex}; use worker::Cors; -use crate::{constants, structures::GitHubAPIResponse}; - -static CACHE_UNSET: SyncLazy<Mutex<bool>> = SyncLazy::new(|| Mutex::new(true)); -static CACHE_ACCESS_COUNT: SyncLazy<Mutex<usize>> = - SyncLazy::new(|| Mutex::new(0)); -static GITHUB_API_CACHE: SyncLazy<Mutex<GitHubAPIResponse>> = - SyncLazy::new(|| Mutex::new(GitHubAPIResponse::default())); +use crate::{ + constants, + structures::{GitHubAPIResponse, Type}, +}; + +static CACHE_UNSET: SyncLazy<Mutex<(bool, bool)>> = + SyncLazy::new(|| Mutex::new((true, true))); +static CACHE_ACCESS_COUNT: SyncLazy<Mutex<(usize, usize)>> = + SyncLazy::new(|| Mutex::new((0, 0))); +static GITHUB_API_CACHE: SyncLazy< + Mutex<(GitHubAPIResponse, GitHubAPIResponse)>, +> = SyncLazy::new(|| { + Mutex::new((GitHubAPIResponse::default(), GitHubAPIResponse::default())) +}); + +use crate::boys; /// # Errors /// if GitHub API is unresponsive pub async fn github_api( + repository: Type, ) -> Result<GitHubAPIResponse, Box<dyn std::error::Error>> { - if *CACHE_UNSET.lock().unwrap() - || *CACHE_ACCESS_COUNT.lock().unwrap() % 50 == 0 - { - *CACHE_UNSET.lock().unwrap() = false; + let unset = if repository == Type::Girls { + (*CACHE_UNSET.lock().unwrap()).0 + } else { + (*CACHE_UNSET.lock().unwrap()).1 + }; + let access_count = if repository == Type::Girls { + (*CACHE_ACCESS_COUNT.lock().unwrap()).0 + } else { + (*CACHE_ACCESS_COUNT.lock().unwrap()).1 + }; + + if unset || access_count % 50 == 0 { + if repository == Type::Girls { + (*CACHE_UNSET.lock().unwrap()).0 = false; + } else { + (*CACHE_UNSET.lock().unwrap()).1 = false; + }; let mut client = reqwest::Client::new() - .get(&*constants::GITHUB_API_ENDPOINT) + .get(if repository == Type::Girls { + &*constants::GITHUB_API_ENDPOINT + } else { + &*boys::GITHUB_API_ENDPOINT + }) .header( "User-Agent", format!("senpy-club/api-worker - {}", env!("VERGEN_GIT_SHA")), @@ -54,25 +81,39 @@ pub async fn github_api( ); } - *GITHUB_API_CACHE.lock().unwrap() = client + let response = client .send() .await? .json::<GitHubAPIResponse>() .await .unwrap_or_default(); - } - *CACHE_ACCESS_COUNT.lock().unwrap() += 1; + if repository == Type::Girls { + (*GITHUB_API_CACHE.lock().unwrap()).0 = response; + } else { + (*GITHUB_API_CACHE.lock().unwrap()).1 = response; + } + } - Ok((*GITHUB_API_CACHE.lock().unwrap()).clone()) + if repository == Type::Girls { + (*CACHE_ACCESS_COUNT.lock().unwrap()).0 += 1; + } else { + (*CACHE_ACCESS_COUNT.lock().unwrap()).1 += 1; + }; + + Ok(if repository == Type::Girls { + (*GITHUB_API_CACHE.lock().unwrap()).0.clone() + } else { + (*GITHUB_API_CACHE.lock().unwrap()).1.clone() + }) } /// # Panics /// if GitHub API is unresponsive -pub async fn filter_languages() -> Vec<String> { +pub async fn filter_languages(repository: Type) -> Vec<String> { let mut languages = vec![]; - for i in github_api().await.unwrap().tree { + for i in github_api(repository).await.unwrap().tree { if i.r#type == "tree" { languages.push(i.path); } @@ -83,19 +124,26 @@ pub async fn filter_languages() -> Vec<String> { /// # Panics /// if GitHub API is unresponsive -pub async fn filter_images_by_language(language: &str) -> Vec<String> { +pub async fn filter_images_by_language( + language: &str, + repository: Type, +) -> Vec<String> { let mut images = vec![]; // URL (percent) encoding of pound symbol to pound symbol let language = language.replace("%23", "#"); - for item in github_api().await.unwrap().tree { + for item in github_api(repository.clone()).await.unwrap().tree { if item.path.split('/').collect::<Vec<&str>>()[0] == language && item.path.contains('/') { images.push(format!( "{}{}", - *constants::GITHUB_USER_CONTENT, + if repository == Type::Girls { + &*constants::GITHUB_USER_CONTENT + } else { + &*boys::GITHUB_USER_CONTENT + }, // Pound symbols to URL (percent) encoding of pound symbol because we // are pushing a URL, not a string item.path.replace('#', "%23") |