aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2022-03-24 02:17:31 -0700
committerFuwn <[email protected]>2022-03-24 02:17:31 -0700
commit993ae59613d41ff25c33f814aed6415a645477dc (patch)
treeae70cc1059a242b00996336844eb1d53e43bf466
parentfeat: cache github api (diff)
downloadapi-worker-993ae59613d41ff25c33f814aed6415a645477dc.tar.xz
api-worker-993ae59613d41ff25c33f814aed6415a645477dc.zip
feat(routes): support for anime boys
-rw-r--r--Cargo.toml2
-rw-r--r--src/boys.rs35
-rw-r--r--src/index.rst6
-rw-r--r--src/lib.rs23
-rw-r--r--src/routes.rs22
-rw-r--r--src/structures.rs6
-rw-r--r--src/utils.rs90
7 files changed, 148 insertions, 36 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 8caad89..683abe6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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
-----
diff --git a/src/lib.rs b/src/lib.rs
index 507c927..f6e2219 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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")