mirror of
https://github.com/okiba-org/backend.git
synced 2025-02-22 01:02:02 +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
|
||||
.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 (
|
||||
id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
|
||||
paste_id VARCHAR(5) NOT NULL,
|
||||
paste_id VARCHAR(6) NOT NULL,
|
||||
content TEXT NOT NULL
|
||||
)
|
33
src/cfg.rs
33
src/cfg.rs
@ -1,16 +1,37 @@
|
||||
pub use config::ConfigError;
|
||||
use config::{File, FileFormat};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub server_addr: String,
|
||||
pub pg: deadpool_postgres::Config,
|
||||
#[derive(Debug, Default, Deserialize, Clone)]
|
||||
pub struct Config {
|
||||
pub db: 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> {
|
||||
let config = config::Config::builder()
|
||||
.add_source(::config::Environment::default())
|
||||
.add_source(File::new("configuration", FileFormat::Yaml))
|
||||
.build()?;
|
||||
config.try_deserialize()
|
||||
}
|
||||
|
24
src/db.rs
24
src/db.rs
@ -24,7 +24,6 @@ pub mod errors {
|
||||
|
||||
#[derive(Display, From, Debug)]
|
||||
pub enum MyError {
|
||||
NotFound,
|
||||
PGError(PGError),
|
||||
PGMError(PGMError),
|
||||
PoolError(PoolError),
|
||||
@ -33,16 +32,19 @@ pub mod errors {
|
||||
|
||||
impl ResponseError for MyError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
match *self {
|
||||
MyError::NotFound => HttpResponse::NotFound().json(json!({
|
||||
"message": "record not found"
|
||||
})),
|
||||
MyError::PoolError(ref err) => HttpResponse::InternalServerError().json(json!({
|
||||
"message": err.to_string()
|
||||
})),
|
||||
_ => HttpResponse::InternalServerError().json(json!({
|
||||
"message": "internal server error"
|
||||
})),
|
||||
match self {
|
||||
MyError::PoolError(ref err) => {
|
||||
log::error!("{}", err.to_string());
|
||||
HttpResponse::InternalServerError().json(json!({
|
||||
"message": err.to_string()
|
||||
}))
|
||||
}
|
||||
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},
|
||||
App, Error, HttpResponse, HttpServer,
|
||||
};
|
||||
use cfg::AppConfig;
|
||||
use cfg::ApplicationConfig;
|
||||
use cfg::Config;
|
||||
use deadpool_postgres::{Client, Pool};
|
||||
use dotenv::dotenv;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use redis::aio::ConnectionManager;
|
||||
use serde_json::json;
|
||||
use std::{
|
||||
str::{self},
|
||||
time::Duration,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use tokio_postgres::NoTls;
|
||||
|
||||
fn generate_endpoint(length: u8) -> String {
|
||||
@ -47,14 +45,18 @@ async fn fetch_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 mut endpoint = generate_endpoint(5);
|
||||
let mut endpoint = generate_endpoint(app_config.paste_id_length);
|
||||
// check if endpoint already exists
|
||||
loop {
|
||||
if db::paste_id_exists(&client, &endpoint).await? {
|
||||
endpoint = generate_endpoint(5)
|
||||
endpoint = generate_endpoint(app_config.paste_id_length)
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -70,37 +72,43 @@ async fn new_paste(db_pool: web::Data<Pool>, body: String) -> Result<HttpRespons
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
dotenv().ok();
|
||||
const ADDR: (&str, u16) = ("127.0.0.1", 8080);
|
||||
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");
|
||||
let pool = config.pg.create_pool(None, NoTls).unwrap();
|
||||
let pool = config.db.create_pool(None, NoTls).unwrap();
|
||||
|
||||
let redis_client =
|
||||
redis::Client::open("redis://127.0.0.1:6379").expect("Couldn't connect to redis database");
|
||||
let redis_client = redis::Client::open(config.app.redis_uri.clone())
|
||||
.expect("Couldn't connect to redis database");
|
||||
let redis_cm = ConnectionManager::new(redis_client).await.unwrap();
|
||||
let redis_backend = RedisBackend::builder(redis_cm).build();
|
||||
|
||||
let server = HttpServer::new(move || {
|
||||
// 5 requests per 60 seconds
|
||||
let input = SimpleInputFunctionBuilder::new(Duration::from_secs(60), 5)
|
||||
.real_ip_key()
|
||||
.build();
|
||||
let input = SimpleInputFunctionBuilder::new(
|
||||
Duration::from_secs(config.app.rate_limit.time_seconds),
|
||||
config.app.rate_limit.request_count,
|
||||
)
|
||||
.real_ip_key()
|
||||
.build();
|
||||
let middleware = RateLimiter::builder(redis_backend.clone(), input)
|
||||
.add_headers()
|
||||
.build();
|
||||
|
||||
App::new()
|
||||
.app_data(web::Data::new(pool.clone()))
|
||||
.app_data(web::Data::new(config.app.clone()))
|
||||
.wrap(middleware)
|
||||
.service(new_paste)
|
||||
.service(fetch_paste)
|
||||
})
|
||||
.bind(ADDR)?
|
||||
.bind((&*config.server.host, config.server.port))?
|
||||
.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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user