mirror of
https://github.com/okiba-org/backend.git
synced 2025-02-22 09:12:06 +00:00
switch to yaml configuration
Signed-off-by: alok8bb <alok8bb@gmail.com>
This commit is contained in:
parent
895b534207
commit
55842e6e3b
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
.env
|
.env
|
||||||
/test
|
/test
|
||||||
|
configuration.yaml
|
19
configuration.example.yaml
Normal file
19
configuration.example.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
server:
|
||||||
|
host: 0.0.0.0
|
||||||
|
port: 7070
|
||||||
|
|
||||||
|
db:
|
||||||
|
user: "oggy"
|
||||||
|
password: "very_secure_password"
|
||||||
|
host: "127.0.0.1"
|
||||||
|
port: "5432"
|
||||||
|
dbname: "okiba"
|
||||||
|
pool:
|
||||||
|
max_size: 16
|
||||||
|
|
||||||
|
app:
|
||||||
|
redis_uri: "redis://127.0.0.1"
|
||||||
|
rate_limit:
|
||||||
|
time_seconds: 60
|
||||||
|
request_count: 10
|
||||||
|
paste_id_length: 6
|
@ -3,6 +3,6 @@ CREATE SCHEMA bin;
|
|||||||
|
|
||||||
CREATE TABLE bin.pastes (
|
CREATE TABLE bin.pastes (
|
||||||
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||||
paste_id VARCHAR(5) NOT NULL,
|
paste_id VARCHAR(6) NOT NULL,
|
||||||
content TEXT NOT NULL
|
content TEXT NOT NULL
|
||||||
)
|
)
|
33
src/cfg.rs
33
src/cfg.rs
@ -1,16 +1,37 @@
|
|||||||
pub use config::ConfigError;
|
pub use config::ConfigError;
|
||||||
|
use config::{File, FileFormat};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize)]
|
#[derive(Debug, Default, Deserialize, Clone)]
|
||||||
pub struct AppConfig {
|
pub struct Config {
|
||||||
pub server_addr: String,
|
pub db: deadpool_postgres::Config,
|
||||||
pub pg: deadpool_postgres::Config,
|
pub server: ServerConfig,
|
||||||
|
pub app: ApplicationConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppConfig {
|
#[derive(Debug, Default, Deserialize, Clone)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
pub port: u16,
|
||||||
|
pub host: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Clone)]
|
||||||
|
pub struct ApplicationConfig {
|
||||||
|
pub redis_uri: String,
|
||||||
|
pub rate_limit: RateLimiterConfig,
|
||||||
|
pub paste_id_length: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Deserialize, Clone)]
|
||||||
|
pub struct RateLimiterConfig {
|
||||||
|
pub time_seconds: u64,
|
||||||
|
pub request_count: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
pub fn from_env() -> Result<Self, ConfigError> {
|
pub fn from_env() -> Result<Self, ConfigError> {
|
||||||
let config = config::Config::builder()
|
let config = config::Config::builder()
|
||||||
.add_source(::config::Environment::default())
|
.add_source(File::new("configuration", FileFormat::Yaml))
|
||||||
.build()?;
|
.build()?;
|
||||||
config.try_deserialize()
|
config.try_deserialize()
|
||||||
}
|
}
|
||||||
|
24
src/db.rs
24
src/db.rs
@ -24,7 +24,6 @@ pub mod errors {
|
|||||||
|
|
||||||
#[derive(Display, From, Debug)]
|
#[derive(Display, From, Debug)]
|
||||||
pub enum MyError {
|
pub enum MyError {
|
||||||
NotFound,
|
|
||||||
PGError(PGError),
|
PGError(PGError),
|
||||||
PGMError(PGMError),
|
PGMError(PGMError),
|
||||||
PoolError(PoolError),
|
PoolError(PoolError),
|
||||||
@ -33,16 +32,19 @@ pub mod errors {
|
|||||||
|
|
||||||
impl ResponseError for MyError {
|
impl ResponseError for MyError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match *self {
|
match self {
|
||||||
MyError::NotFound => HttpResponse::NotFound().json(json!({
|
MyError::PoolError(ref err) => {
|
||||||
"message": "record not found"
|
log::error!("{}", err.to_string());
|
||||||
})),
|
HttpResponse::InternalServerError().json(json!({
|
||||||
MyError::PoolError(ref err) => HttpResponse::InternalServerError().json(json!({
|
"message": err.to_string()
|
||||||
"message": err.to_string()
|
}))
|
||||||
})),
|
}
|
||||||
_ => HttpResponse::InternalServerError().json(json!({
|
error => {
|
||||||
"message": "internal server error"
|
log::error!("{}", error.to_string());
|
||||||
})),
|
HttpResponse::InternalServerError().json(json!({
|
||||||
|
"message": "internal server error"
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
src/main.rs
46
src/main.rs
@ -10,16 +10,14 @@ use actix_web::{
|
|||||||
web::{self},
|
web::{self},
|
||||||
App, Error, HttpResponse, HttpServer,
|
App, Error, HttpResponse, HttpServer,
|
||||||
};
|
};
|
||||||
use cfg::AppConfig;
|
use cfg::ApplicationConfig;
|
||||||
|
use cfg::Config;
|
||||||
use deadpool_postgres::{Client, Pool};
|
use deadpool_postgres::{Client, Pool};
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
use rand::{distributions::Alphanumeric, Rng};
|
||||||
use redis::aio::ConnectionManager;
|
use redis::aio::ConnectionManager;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::{
|
use std::time::Duration;
|
||||||
str::{self},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
use tokio_postgres::NoTls;
|
use tokio_postgres::NoTls;
|
||||||
|
|
||||||
fn generate_endpoint(length: u8) -> String {
|
fn generate_endpoint(length: u8) -> String {
|
||||||
@ -47,14 +45,18 @@ async fn fetch_paste(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[post("/paste")]
|
#[post("/paste")]
|
||||||
async fn new_paste(db_pool: web::Data<Pool>, body: String) -> Result<HttpResponse, Error> {
|
async fn new_paste(
|
||||||
|
db_pool: web::Data<Pool>,
|
||||||
|
app_config: web::Data<ApplicationConfig>,
|
||||||
|
body: String,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
let client: Client = db_pool.get().await.map_err(MyError::PoolError)?;
|
let client: Client = db_pool.get().await.map_err(MyError::PoolError)?;
|
||||||
|
|
||||||
let mut endpoint = generate_endpoint(5);
|
let mut endpoint = generate_endpoint(app_config.paste_id_length);
|
||||||
// check if endpoint already exists
|
// check if endpoint already exists
|
||||||
loop {
|
loop {
|
||||||
if db::paste_id_exists(&client, &endpoint).await? {
|
if db::paste_id_exists(&client, &endpoint).await? {
|
||||||
endpoint = generate_endpoint(5)
|
endpoint = generate_endpoint(app_config.paste_id_length)
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -70,37 +72,43 @@ async fn new_paste(db_pool: web::Data<Pool>, body: String) -> Result<HttpRespons
|
|||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
const ADDR: (&str, u16) = ("127.0.0.1", 8080);
|
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
let config = AppConfig::from_env().unwrap();
|
let config = Config::from_env().unwrap();
|
||||||
log::info!("Connecting database");
|
log::info!("Connecting database");
|
||||||
let pool = config.pg.create_pool(None, NoTls).unwrap();
|
let pool = config.db.create_pool(None, NoTls).unwrap();
|
||||||
|
|
||||||
let redis_client =
|
let redis_client = redis::Client::open(config.app.redis_uri.clone())
|
||||||
redis::Client::open("redis://127.0.0.1:6379").expect("Couldn't connect to redis database");
|
.expect("Couldn't connect to redis database");
|
||||||
let redis_cm = ConnectionManager::new(redis_client).await.unwrap();
|
let redis_cm = ConnectionManager::new(redis_client).await.unwrap();
|
||||||
let redis_backend = RedisBackend::builder(redis_cm).build();
|
let redis_backend = RedisBackend::builder(redis_cm).build();
|
||||||
|
|
||||||
let server = HttpServer::new(move || {
|
let server = HttpServer::new(move || {
|
||||||
// 5 requests per 60 seconds
|
let input = SimpleInputFunctionBuilder::new(
|
||||||
let input = SimpleInputFunctionBuilder::new(Duration::from_secs(60), 5)
|
Duration::from_secs(config.app.rate_limit.time_seconds),
|
||||||
.real_ip_key()
|
config.app.rate_limit.request_count,
|
||||||
.build();
|
)
|
||||||
|
.real_ip_key()
|
||||||
|
.build();
|
||||||
let middleware = RateLimiter::builder(redis_backend.clone(), input)
|
let middleware = RateLimiter::builder(redis_backend.clone(), input)
|
||||||
.add_headers()
|
.add_headers()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(web::Data::new(pool.clone()))
|
.app_data(web::Data::new(pool.clone()))
|
||||||
|
.app_data(web::Data::new(config.app.clone()))
|
||||||
.wrap(middleware)
|
.wrap(middleware)
|
||||||
.service(new_paste)
|
.service(new_paste)
|
||||||
.service(fetch_paste)
|
.service(fetch_paste)
|
||||||
})
|
})
|
||||||
.bind(ADDR)?
|
.bind((&*config.server.host, config.server.port))?
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
log::info!("Starting the server at http://{}:{}", ADDR.0, ADDR.1);
|
log::info!(
|
||||||
|
"Starting the server at http://{}:{}",
|
||||||
|
config.server.host,
|
||||||
|
config.server.port
|
||||||
|
);
|
||||||
|
|
||||||
server.await
|
server.await
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user