mirror of
https://codeberg.org/Mo8it/git-webhook-client
synced 2024-11-24 11:21:36 +00:00
Use anyhow and simplelog
This commit is contained in:
parent
6e297455b9
commit
fb23798d78
8 changed files with 75 additions and 35 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
*.log
|
||||||
/Cargo.lock
|
/Cargo.lock
|
||||||
/config.json
|
/config.json
|
||||||
/db/
|
/db/
|
||||||
|
|
20
Cargo.toml
20
Cargo.toml
|
@ -1,23 +1,27 @@
|
||||||
[package]
|
[package]
|
||||||
name = "git-webhook-client"
|
name = "git-webhook-client"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
authors = ["Mo Bitar <mo8it@proton.me>"]
|
authors = ["Mo Bitar <mo8it@proton.me>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
readme = "README.adoc"
|
readme = "README.adoc"
|
||||||
license-file = "LICENSE"
|
repository = "https://codeberg.org/Mo8it/git-webhook-client"
|
||||||
|
license-file = "LICENSE.txt"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4.22"
|
anyhow = "1.0"
|
||||||
diesel = { version = "2.0.2", features = [
|
chrono = "0.4"
|
||||||
|
diesel = { version = "2.0", features = [
|
||||||
"r2d2",
|
"r2d2",
|
||||||
"sqlite",
|
"sqlite",
|
||||||
"returning_clauses_for_sqlite_3_35",
|
"returning_clauses_for_sqlite_3_35",
|
||||||
"without-deprecated",
|
"without-deprecated",
|
||||||
] }
|
] }
|
||||||
hex = "0.4.3"
|
hex = "0.4"
|
||||||
hmac = "0.12.1"
|
hmac = "0.12"
|
||||||
|
log = "0.4"
|
||||||
rocket = "0.5.0-rc.2"
|
rocket = "0.5.0-rc.2"
|
||||||
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
|
rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["tera"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0.87"
|
serde_json = "1.0"
|
||||||
sha2 = "0.10.6"
|
sha2 = "0.10"
|
||||||
|
simplelog = "0.12"
|
||||||
|
|
|
@ -22,7 +22,7 @@ Currently, only Gitea is supported. If you want support for Gitlab or Github, th
|
||||||
|
|
||||||
=== Configuration
|
=== Configuration
|
||||||
|
|
||||||
The program looks for the configuration file `config.json` that contains the following:
|
The program looks for the configuration file configured with the environment variable `GWC_CONFIG_FILE` that contains the following:
|
||||||
|
|
||||||
. `secret`: The secret of the webhook.
|
. `secret`: The secret of the webhook.
|
||||||
. `base_url`: The base_url of the webhook client.
|
. `base_url`: The base_url of the webhook client.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Hook {
|
pub struct Hook {
|
||||||
|
@ -15,19 +15,18 @@ pub struct Hook {
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
|
pub log_file: String,
|
||||||
pub hooks: Vec<Hook>,
|
pub hooks: Vec<Hook>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let config_path = Path::new("config.json");
|
let config_file_var = "GWC_CONFIG_FILE";
|
||||||
let config_file = File::open(config_path).unwrap_or_else(|_| {
|
let config_path = env::var(config_file_var)
|
||||||
panic!(
|
.unwrap_or_else(|_| panic!("Environment variable {config_file_var} missing!"));
|
||||||
"Can not open the config file at the path {}!",
|
|
||||||
config_path
|
let config_file = File::open(&config_path).unwrap_or_else(|e| {
|
||||||
.to_str()
|
panic!("Can not open the config file at the path {config_path}: {e}")
|
||||||
.expect("Can not convert the config file path into a string")
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
let config_reader = BufReader::new(config_file);
|
let config_reader = BufReader::new(config_file);
|
||||||
let config: Self =
|
let config: Self =
|
||||||
|
|
27
src/db.rs
27
src/db.rs
|
@ -1,6 +1,8 @@
|
||||||
|
use anyhow::{Context, Result};
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
||||||
|
use log::error;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use crate::config::Hook;
|
use crate::config::Hook;
|
||||||
|
@ -10,8 +12,10 @@ use crate::schema::hooklog;
|
||||||
pub type DBPool = Pool<ConnectionManager<SqliteConnection>>;
|
pub type DBPool = Pool<ConnectionManager<SqliteConnection>>;
|
||||||
|
|
||||||
pub fn establish_connection_pool() -> DBPool {
|
pub fn establish_connection_pool() -> DBPool {
|
||||||
let database_url =
|
let database_url_var = "DATABASE_URL";
|
||||||
env::var("DATABASE_URL").expect("Environment variable DATABASE_URL missing!");
|
let database_url = env::var(database_url_var)
|
||||||
|
.unwrap_or_else(|_| panic!("Environment variable {database_url_var} missing!"));
|
||||||
|
|
||||||
let manager = ConnectionManager::<SqliteConnection>::new(&database_url);
|
let manager = ConnectionManager::<SqliteConnection>::new(&database_url);
|
||||||
|
|
||||||
Pool::builder()
|
Pool::builder()
|
||||||
|
@ -19,14 +23,11 @@ pub fn establish_connection_pool() -> DBPool {
|
||||||
.expect("Could not build database connection pool!")
|
.expect("Could not build database connection pool!")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_conn(
|
fn get_conn(pool: &DBPool) -> Result<PooledConnection<ConnectionManager<SqliteConnection>>> {
|
||||||
pool: &DBPool,
|
pool.get().context("Could not get database pool!")
|
||||||
) -> Result<PooledConnection<ConnectionManager<SqliteConnection>>, String> {
|
|
||||||
pool.get()
|
|
||||||
.map_err(|_| "Could not get database pool!".to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_hook_log(pool: &DBPool, hook: &Hook) -> Result<HookLog, String> {
|
pub fn add_hook_log(pool: &DBPool, hook: &Hook) -> Result<HookLog> {
|
||||||
let conn = &mut get_conn(pool)?;
|
let conn = &mut get_conn(pool)?;
|
||||||
|
|
||||||
let command_with_args = hook.command.to_owned() + " " + &hook.args.join(" ");
|
let command_with_args = hook.command.to_owned() + " " + &hook.args.join(" ");
|
||||||
|
@ -41,7 +42,7 @@ pub fn add_hook_log(pool: &DBPool, hook: &Hook) -> Result<HookLog, String> {
|
||||||
diesel::insert_into(hooklog::table)
|
diesel::insert_into(hooklog::table)
|
||||||
.values(&new_hook_log)
|
.values(&new_hook_log)
|
||||||
.get_result::<HookLog>(conn)
|
.get_result::<HookLog>(conn)
|
||||||
.map_err(|e| e.to_string())
|
.context("Could not insert hook log!")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_hook_log(
|
pub fn fill_hook_log(
|
||||||
|
@ -54,7 +55,7 @@ pub fn fill_hook_log(
|
||||||
let conn = &mut match get_conn(pool) {
|
let conn = &mut match get_conn(pool) {
|
||||||
Ok(pool) => pool,
|
Ok(pool) => pool,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error while trying to fill hook log: {e}");
|
error!("Could not get a database pool connection to fill hook log with id {hook_log_id}: {e}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -73,12 +74,12 @@ pub fn fill_hook_log(
|
||||||
{
|
{
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Could not update hook log: {e}");
|
error!("Could not update hook log with id {hook_log_id}: {e}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hook_log(pool: &DBPool, id: i32) -> Result<HookLog, String> {
|
pub fn get_hook_log(pool: &DBPool, id: i32) -> Result<HookLog> {
|
||||||
// id=0 not allowed!
|
// id=0 not allowed!
|
||||||
|
|
||||||
let conn = &mut get_conn(pool)?;
|
let conn = &mut get_conn(pool)?;
|
||||||
|
@ -92,5 +93,5 @@ pub fn get_hook_log(pool: &DBPool, id: i32) -> Result<HookLog, String> {
|
||||||
.first(conn)
|
.first(conn)
|
||||||
};
|
};
|
||||||
|
|
||||||
hl.map_err(|e| e.to_string())
|
hl.context("Could not get hook log!")
|
||||||
}
|
}
|
||||||
|
|
29
src/logging.rs
Normal file
29
src/logging.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode, WriteLogger};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
|
||||||
|
pub fn init_logger(config: &config::Config) {
|
||||||
|
let logger = if cfg!(debug_assertions) {
|
||||||
|
TermLogger::init(
|
||||||
|
LevelFilter::Debug,
|
||||||
|
simplelog::Config::default(),
|
||||||
|
TerminalMode::Mixed,
|
||||||
|
ColorChoice::Auto,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
WriteLogger::init(
|
||||||
|
LevelFilter::Info,
|
||||||
|
simplelog::Config::default(),
|
||||||
|
OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(&config.log_file)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
panic!("Could not open the log file {}: {e}", &config.log_file)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.expect("Could not initialize the logger!");
|
||||||
|
}
|
10
src/main.rs
10
src/main.rs
|
@ -1,19 +1,27 @@
|
||||||
mod config;
|
mod config;
|
||||||
mod db;
|
mod db;
|
||||||
mod guards;
|
mod guards;
|
||||||
|
mod logging;
|
||||||
mod models;
|
mod models;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod states;
|
mod states;
|
||||||
|
|
||||||
|
use log::info;
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
|
|
||||||
#[rocket::launch]
|
#[rocket::launch]
|
||||||
fn rocket() -> _ {
|
fn rocket() -> _ {
|
||||||
|
let config = config::Config::new();
|
||||||
|
|
||||||
|
logging::init_logger(&config);
|
||||||
|
|
||||||
|
info!("Starting client");
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.mount("/", rocket::routes![routes::index])
|
.mount("/", rocket::routes![routes::index])
|
||||||
.mount("/api", rocket::routes![routes::trigger])
|
.mount("/api", rocket::routes![routes::trigger])
|
||||||
.manage(states::DB::new())
|
.manage(states::DB::new())
|
||||||
.manage(states::Config::new())
|
.manage(states::Config::new(config))
|
||||||
.attach(Template::fairing())
|
.attach(Template::fairing())
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,7 @@ pub struct Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new() -> Self {
|
pub fn new(config: config::Config) -> Self {
|
||||||
let config = config::Config::new();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
secret: config.secret.as_bytes().to_owned(),
|
secret: config.secret.as_bytes().to_owned(),
|
||||||
base_url: config.base_url,
|
base_url: config.base_url,
|
||||||
|
|
Loading…
Reference in a new issue