generated from ElnuDev/rust-project
Compare commits
No commits in common. "befc0c0ee38ab3f63802034b0a7feb660604d215" and "7998ea461bc451de6ea8702c505cee6a9b1b18a2" have entirely different histories.
befc0c0ee3
...
7998ea461b
6 changed files with 5 additions and 1777 deletions
1679
Cargo.lock
generated
1679
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tatoeba-api"
|
name = ""
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4.3.1"
|
|
||||||
derive_more = "0.99.17"
|
|
||||||
mime = "0.3.17"
|
|
||||||
reqwest = "0.11.18"
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pkgs.mkShell {
|
||||||
ruststable
|
ruststable
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
bacon
|
bacon
|
||||||
pkg-config
|
#pkg-config
|
||||||
openssl
|
#openssl
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
42
src/error.rs
42
src/error.rs
|
@ -1,42 +0,0 @@
|
||||||
use actix_web::{HttpResponse, ResponseError};
|
|
||||||
use derive_more::From;
|
|
||||||
use std::fmt::{self, Display};
|
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(From, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
TatoebaApi(reqwest::Error),
|
|
||||||
NotHuman { target: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{:?}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ResponseError for Error {
|
|
||||||
fn status_code(&self) -> reqwest::StatusCode {
|
|
||||||
use reqwest::StatusCode;
|
|
||||||
use Error::*;
|
|
||||||
match self {
|
|
||||||
// 503 Service Unavailable
|
|
||||||
TatoebaApi(error) => error.status().unwrap_or(StatusCode::SERVICE_UNAVAILABLE),
|
|
||||||
// 403 Forbidden
|
|
||||||
NotHuman { .. } => StatusCode::FORBIDDEN,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_response(&self) -> HttpResponse<actix_web::body::BoxBody> {
|
|
||||||
HttpResponse::build(self.status_code()).body(match self {
|
|
||||||
Self::NotHuman { target } => format!(
|
|
||||||
"It looks like you're accessing the Tatoeba API proxy from a script!\n\
|
|
||||||
Tatoeba CORS restrictions do not apply outside of browsers, so please access the API directly:\n\
|
|
||||||
{target}\n\
|
|
||||||
If you feel this is mistake, please open an issue:\n\
|
|
||||||
https://codeberg.org/ElnuDev/tatoeba-api-rs"),
|
|
||||||
_ => self.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
30
src/main.rs
30
src/main.rs
|
@ -1,29 +1,3 @@
|
||||||
mod error;
|
fn main() {
|
||||||
pub use error::{Error, Result};
|
println!("Hello, world!");
|
||||||
|
|
||||||
pub mod utils;
|
|
||||||
use utils::is_human;
|
|
||||||
|
|
||||||
use actix_web::{get, http::header, App, HttpRequest, HttpResponse, HttpServer, Responder};
|
|
||||||
|
|
||||||
pub const TATOEBA_API: &str = "https://tatoeba.org/en/api_v0/search";
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
async fn root(request: HttpRequest) -> Result<impl Responder> {
|
|
||||||
let target = format!("{TATOEBA_API}?{}", request.query_string());
|
|
||||||
if !is_human(&request) {
|
|
||||||
return Err(Error::NotHuman { target });
|
|
||||||
}
|
|
||||||
let resp = reqwest::get(target).await?;
|
|
||||||
Ok(HttpResponse::Ok()
|
|
||||||
.append_header(header::ContentType(mime::APPLICATION_JSON))
|
|
||||||
.body(resp.text().await?))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[actix_web::main]
|
|
||||||
async fn main() -> std::io::Result<()> {
|
|
||||||
HttpServer::new(|| App::new().service(root))
|
|
||||||
.bind(("127.0.0.1", 3001))?
|
|
||||||
.run()
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
21
src/utils.rs
21
src/utils.rs
|
@ -1,21 +0,0 @@
|
||||||
use actix_web::{http::header, HttpRequest};
|
|
||||||
|
|
||||||
pub fn is_human(request: &HttpRequest) -> bool {
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
|
|
||||||
const HUMANS: &[&str] = &[
|
|
||||||
"Firefox", "Chrome", // Chrome and Chromium browsers
|
|
||||||
"Opera", // Old Presto-based Opera
|
|
||||||
"Mobile", // Safari
|
|
||||||
"Trident", // Internet Explorer
|
|
||||||
];
|
|
||||||
request
|
|
||||||
.headers()
|
|
||||||
.get(header::USER_AGENT)
|
|
||||||
.and_then(|header| header.to_str().ok())
|
|
||||||
.map(|ua| {
|
|
||||||
HUMANS
|
|
||||||
.iter()
|
|
||||||
.any(|&human| ua.contains(human))
|
|
||||||
})
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue