Changed config format
This commit is contained in:
parent
e0eeccefe5
commit
408bf0b3fa
7 changed files with 97 additions and 43 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
config.toml
|
|
@ -8,10 +8,12 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
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 = { 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 = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0.51"
|
serde_json = "1.0.51"
|
||||||
sqlx = { version = "0.3", features = [ "mysql" ] }
|
sqlx = { version = "0.3", features = [ "mysql" ] }
|
||||||
rand = "0.8.0"
|
rand = "0.8.0"
|
||||||
|
structopt = "0.3.22"
|
||||||
|
toml = "0.5.8"
|
29
src/config.rs
Normal file
29
src/config.rs
Normal 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() }
|
||||||
|
}
|
||||||
|
}
|
37
src/main.rs
37
src/main.rs
|
@ -1,25 +1,42 @@
|
||||||
use std::{io, env};
|
use std::{env, io, path::PathBuf};
|
||||||
|
use config::Config;
|
||||||
use sqlx::MySqlPool;
|
use sqlx::MySqlPool;
|
||||||
use std::net::SocketAddr;
|
use structopt::StructOpt;
|
||||||
use axum::Router;
|
use axum::{Router, body::Body, http::{HeaderValue, Request, header}};
|
||||||
use tower_http::add_extension::AddExtensionLayer;
|
use tower_http::{add_extension::AddExtensionLayer, set_header::SetResponseHeaderLayer};
|
||||||
|
|
||||||
mod v1;
|
mod v1;
|
||||||
|
mod config;
|
||||||
|
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
struct Opt {
|
||||||
|
#[structopt(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "config file to use",
|
||||||
|
default_value = "./config.toml"
|
||||||
|
)]
|
||||||
|
config: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
|
||||||
let database_url = env::var("DBURL").unwrap();
|
let opt = Opt::from_args();
|
||||||
let db_pool = MySqlPool::new(&database_url).await.unwrap();
|
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()
|
let app = Router::new()
|
||||||
.nest("/v1", v1::routes())
|
.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(&config.addr)
|
||||||
|
|
||||||
axum::Server::bind(&addr)
|
|
||||||
.serve(app.into_make_service())
|
.serve(app.into_make_service())
|
||||||
.await
|
.await
|
||||||
.expect("Something went wrong :(");
|
.expect("Something went wrong :(");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub struct Meme {
|
||||||
pub category: String,
|
pub category: String,
|
||||||
pub user: String,
|
pub user: String,
|
||||||
pub timestamp: String,
|
pub timestamp: String,
|
||||||
|
pub ipfs: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::config::ConfVars;
|
||||||
use crate::v1::models::*;
|
use crate::v1::models::*;
|
||||||
use sqlx::{MySqlPool, Error};
|
use sqlx::{MySqlPool, Error};
|
||||||
use axum::{Router, Json};
|
use axum::{Router, Json};
|
||||||
|
@ -7,8 +8,8 @@ use axum::handler::get;
|
||||||
use axum::extract::{Query, Extension};
|
use axum::extract::{Query, Extension};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
|
|
||||||
async fn meme(params: Query<MemeIDQuery>, Extension(db_pool): Extension<MySqlPool>) -> impl IntoResponse {
|
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).await;
|
let q = Meme::get(params.id, &db_pool, vars.cdn).await;
|
||||||
match q {
|
match q {
|
||||||
Ok(meme) => (StatusCode::OK, Json(MemeResponse {
|
Ok(meme) => (StatusCode::OK, Json(MemeResponse {
|
||||||
status: 200,
|
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 {
|
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).await;
|
let q = Meme::get_all(params.0, &db_pool, vars.cdn).await;
|
||||||
match q {
|
match q {
|
||||||
Ok(memes) => (StatusCode::OK, Json(MemesResponse {
|
Ok(memes) => (StatusCode::OK, Json(MemesResponse {
|
||||||
status: 200,
|
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 {
|
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).await;
|
let q = Meme::get_random(params.0, &db_pool, vars.cdn).await;
|
||||||
match q {
|
match q {
|
||||||
Ok(random) => (StatusCode::OK, Json(MemeResponse {
|
Ok(random) => (StatusCode::OK, Json(MemeResponse {
|
||||||
status: 200,
|
status: 200,
|
||||||
|
|
|
@ -10,72 +10,75 @@ pub struct DBMeme {
|
||||||
pub userdir: String,
|
pub userdir: String,
|
||||||
pub category: String,
|
pub category: String,
|
||||||
pub timestamp: i64,
|
pub timestamp: i64,
|
||||||
|
pub ipfs: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Meme {
|
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)
|
pub fn new(meme: DBMeme, cdn: String) -> Self {
|
||||||
.map(|row: MySqlRow| Meme::from(DBMeme {
|
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"),
|
id: row.get("id"),
|
||||||
filename: row.get("filename"),
|
filename: row.get("filename"),
|
||||||
user: row.get("name"),
|
user: row.get("name"),
|
||||||
userdir: row.get("user"),
|
userdir: row.get("user"),
|
||||||
category: row.get("category"),
|
category: row.get("category"),
|
||||||
timestamp: row.get("ts"),
|
timestamp: row.get("ts"),
|
||||||
}))
|
ipfs: row.get("cid"),
|
||||||
|
}, cdn.clone()))
|
||||||
.fetch_one(pool).await?;
|
.fetch_one(pool).await?;
|
||||||
Ok(q)
|
Ok(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_all(params: MemeFilterQuery, pool: &MySqlPool) -> Result<Vec<Meme>> {
|
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 FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY memes.id")
|
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(params.category.unwrap_or(String::from("%")))
|
||||||
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
|
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
|
||||||
.bind(format!("%{}%", params.search.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"),
|
id: row.get("id"),
|
||||||
filename: row.get("filename"),
|
filename: row.get("filename"),
|
||||||
user: row.get("name"),
|
user: row.get("name"),
|
||||||
userdir: row.get("user"),
|
userdir: row.get("user"),
|
||||||
category: row.get("category"),
|
category: row.get("category"),
|
||||||
timestamp: row.get("ts"),
|
timestamp: row.get("ts"),
|
||||||
}))
|
ipfs: row.get("cid"),
|
||||||
|
}, cdn.clone()))
|
||||||
.fetch_all(pool).await?;
|
.fetch_all(pool).await?;
|
||||||
Ok(q)
|
Ok(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_random(params: MemeFilterQuery, pool: &MySqlPool) -> Result<Meme> {
|
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 FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY RAND() LIMIT 1")
|
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(params.category.unwrap_or(String::from("%")))
|
||||||
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
|
.bind(format!("%{}%", params.user.unwrap_or(String::from(""))))
|
||||||
.bind(format!("%{}%", params.search.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"),
|
id: row.get("id"),
|
||||||
filename: row.get("filename"),
|
filename: row.get("filename"),
|
||||||
user: row.get("name"),
|
user: row.get("name"),
|
||||||
userdir: row.get("user"),
|
userdir: row.get("user"),
|
||||||
category: row.get("category"),
|
category: row.get("category"),
|
||||||
timestamp: row.get("ts"),
|
timestamp: row.get("ts"),
|
||||||
}))
|
ipfs: row.get("cid"),
|
||||||
|
}, cdn.clone()))
|
||||||
.fetch_one(pool).await?;
|
.fetch_one(pool).await?;
|
||||||
Ok(q)
|
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 {
|
impl Category {
|
||||||
pub async fn get(id: &String, pool: &MySqlPool) -> Result<Category> {
|
pub async fn get(id: &String, pool: &MySqlPool) -> Result<Category> {
|
||||||
let q: Category = sqlx::query("SELECT * FROM categories WHERE id=?").bind(id)
|
let q: Category = sqlx::query("SELECT * FROM categories WHERE id=?").bind(id)
|
||||||
|
|
Loading…
Reference in a new issue