Changed config format

This commit is contained in:
Timo Ley 2021-12-17 23:50:03 +01:00
parent e0eeccefe5
commit 408bf0b3fa
7 changed files with 97 additions and 43 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
.idea
*.iml
Cargo.lock
config.toml

View file

@ -8,10 +8,12 @@ edition = "2018"
[dependencies]
tokio = { version = "1.0", features = ["full"] }
axum = "0.2.1"
axum = { version = "0.2.8", features = ["headers"] }
tower = { version = "0.4", features = ["util", "timeout"] }
tower-http = { version = "0.1", features = ["add-extension", "trace"] }
tower-http = { version = "0.1", features = ["add-extension", "trace", "fs", "set-header"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.51"
sqlx = { version = "0.3", features = [ "mysql" ] }
rand = "0.8.0"
structopt = "0.3.22"
toml = "0.5.8"

29
src/config.rs Normal file
View file

@ -0,0 +1,29 @@
use std::net::SocketAddr;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Config {
pub addr: SocketAddr,
pub database: String,
pub cdn: String,
}
pub struct ConfVars {
pub cdn: String,
}
impl Config {
pub fn vars(&self) -> ConfVars {
ConfVars {
cdn: self.cdn.clone(),
}
}
}
impl Clone for ConfVars {
fn clone(&self) -> Self {
Self { cdn: self.cdn.clone() }
}
}

View file

@ -1,25 +1,42 @@
use std::{io, env};
use std::{env, io, path::PathBuf};
use config::Config;
use sqlx::MySqlPool;
use std::net::SocketAddr;
use axum::Router;
use tower_http::add_extension::AddExtensionLayer;
use structopt::StructOpt;
use axum::{Router, body::Body, http::{HeaderValue, Request, header}};
use tower_http::{add_extension::AddExtensionLayer, set_header::SetResponseHeaderLayer};
mod v1;
mod config;
#[derive(StructOpt)]
struct Opt {
#[structopt(
short,
long,
help = "config file to use",
default_value = "./config.toml"
)]
config: PathBuf,
}
#[tokio::main]
async fn main() {
let database_url = env::var("DBURL").unwrap();
let db_pool = MySqlPool::new(&database_url).await.unwrap();
let opt = Opt::from_args();
let config = std::fs::read(&opt.config).expect("Config file reading error");
let config = toml::from_slice::<Config>(&config).expect("Config file parsing error");
let db_pool = MySqlPool::new(&config.database).await.expect("Database connection error");
let app = Router::new()
.nest("/v1", v1::routes())
.layer(AddExtensionLayer::new(db_pool));
.layer(AddExtensionLayer::new(db_pool))
.layer(AddExtensionLayer::new(config.vars()))
.layer(SetResponseHeaderLayer::<_, Request<Body>>::if_not_present(header::ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*")));
let addr: SocketAddr = env::var("LISTEN").expect("The LISTEN env var ist not set").parse().expect("The LISTEN env var is set incorrectly");
axum::Server::bind(&addr)
axum::Server::bind(&config.addr)
.serve(app.into_make_service())
.await
.expect("Something went wrong :(");
}

View file

@ -7,6 +7,7 @@ pub struct Meme {
pub category: String,
pub user: String,
pub timestamp: String,
pub ipfs: Option<String>,
}
#[derive(Serialize)]

View file

@ -1,3 +1,4 @@
use crate::config::ConfVars;
use crate::v1::models::*;
use sqlx::{MySqlPool, Error};
use axum::{Router, Json};
@ -7,8 +8,8 @@ use axum::handler::get;
use axum::extract::{Query, Extension};
use axum::http::StatusCode;
async fn meme(params: Query<MemeIDQuery>, Extension(db_pool): Extension<MySqlPool>) -> impl IntoResponse {
let q = Meme::get(params.id, &db_pool).await;
async fn meme(params: Query<MemeIDQuery>, Extension(db_pool): Extension<MySqlPool>, Extension(vars): Extension<ConfVars>) -> impl IntoResponse {
let q = Meme::get(params.id, &db_pool, vars.cdn).await;
match q {
Ok(meme) => (StatusCode::OK, Json(MemeResponse {
status: 200,
@ -30,8 +31,8 @@ async fn meme(params: Query<MemeIDQuery>, Extension(db_pool): Extension<MySqlPoo
}
}
async fn memes(params: Query<MemeFilterQuery>, Extension(db_pool): Extension<MySqlPool>) -> impl IntoResponse {
let q = Meme::get_all(params.0, &db_pool).await;
async fn memes(params: Query<MemeFilterQuery>, Extension(db_pool): Extension<MySqlPool>, Extension(vars): Extension<ConfVars>) -> impl IntoResponse {
let q = Meme::get_all(params.0, &db_pool, vars.cdn).await;
match q {
Ok(memes) => (StatusCode::OK, Json(MemesResponse {
status: 200,
@ -101,8 +102,8 @@ async fn users(Extension(db_pool): Extension<MySqlPool>) -> impl IntoResponse {
}
}
async fn random(params: Query<MemeFilterQuery>, Extension(db_pool): Extension<MySqlPool>) -> impl IntoResponse {
let q = Meme::get_random(params.0, &db_pool).await;
async fn random(params: Query<MemeFilterQuery>, Extension(db_pool): Extension<MySqlPool>, Extension(vars): Extension<ConfVars>) -> impl IntoResponse {
let q = Meme::get_random(params.0, &db_pool, vars.cdn).await;
match q {
Ok(random) => (StatusCode::OK, Json(MemeResponse {
status: 200,

View file

@ -10,72 +10,75 @@ pub struct DBMeme {
pub userdir: String,
pub category: String,
pub timestamp: i64,
pub ipfs: Option<String>,
}
impl Meme {
pub async fn get(id: i32, pool: &MySqlPool) -> Result<Meme> {
let q: Meme = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts FROM memes, users WHERE memes.user = users.id AND memes.id=?").bind(id)
.map(|row: MySqlRow| Meme::from(DBMeme {
pub fn new(meme: DBMeme, cdn: String) -> Self {
Meme {
id: meme.id.to_string(),
link: format!("{}/{}/{}", cdn, meme.userdir, meme.filename),
category: meme.category,
user: meme.user,
timestamp: meme.timestamp.to_string(),
ipfs: meme.ipfs,
}
}
pub async fn get(id: i32, pool: &MySqlPool, cdn: String) -> Result<Meme> {
let q: Meme = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND memes.id=?").bind(id)
.map(|row: MySqlRow| Meme::new(DBMeme {
id: row.get("id"),
filename: row.get("filename"),
user: row.get("name"),
userdir: row.get("user"),
category: row.get("category"),
timestamp: row.get("ts"),
}))
ipfs: row.get("cid"),
}, cdn.clone()))
.fetch_one(pool).await?;
Ok(q)
}
pub async fn get_all(params: MemeFilterQuery, pool: &MySqlPool) -> Result<Vec<Meme>> {
let q: Vec<Meme> = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY memes.id")
pub async fn get_all(params: MemeFilterQuery, pool: &MySqlPool, cdn: String) -> Result<Vec<Meme>> {
let q: Vec<Meme> = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY memes.id")
.bind(params.category.unwrap_or(String::from("%")))
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
.bind(format!("%{}%", params.search.unwrap_or(String::from(""))))
.map(|row: MySqlRow| Meme::from(DBMeme {
.map(|row: MySqlRow| Meme::new(DBMeme {
id: row.get("id"),
filename: row.get("filename"),
user: row.get("name"),
userdir: row.get("user"),
category: row.get("category"),
timestamp: row.get("ts"),
}))
ipfs: row.get("cid"),
}, cdn.clone()))
.fetch_all(pool).await?;
Ok(q)
}
pub async fn get_random(params: MemeFilterQuery, pool: &MySqlPool) -> Result<Meme> {
let q: Meme = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY RAND() LIMIT 1")
pub async fn get_random(params: MemeFilterQuery, pool: &MySqlPool, cdn: String) -> Result<Meme> {
let q: Meme = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY RAND() LIMIT 1")
.bind(params.category.unwrap_or(String::from("%")))
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
.bind(format!("%{}%", params.search.unwrap_or(String::from(""))))
.map(|row: MySqlRow| Meme::from(DBMeme {
.map(|row: MySqlRow| Meme::new(DBMeme {
id: row.get("id"),
filename: row.get("filename"),
user: row.get("name"),
userdir: row.get("user"),
category: row.get("category"),
timestamp: row.get("ts"),
}))
ipfs: row.get("cid"),
}, cdn.clone()))
.fetch_one(pool).await?;
Ok(q)
}
}
impl From<DBMeme> for Meme {
fn from(meme: DBMeme) -> Self {
Meme {
id: meme.id.to_string(),
link: format!("{}/{}/{}", env::var("CDNURL").unwrap(), meme.userdir, meme.filename),
category: meme.category,
user: meme.user,
timestamp: meme.timestamp.to_string(),
}
}
}
impl Category {
pub async fn get(id: &String, pool: &MySqlPool) -> Result<Category> {
let q: Category = sqlx::query("SELECT * FROM categories WHERE id=?").bind(id)