load configuration and database only once

This commit is contained in:
Miraty 2024-04-23 01:33:39 +02:00
parent 973d1c5b41
commit b2a6d8d02a
5 changed files with 158 additions and 86 deletions

47
Cargo.lock generated
View File

@ -397,6 +397,7 @@ checksum = "03fc05c17098f21b89bc7d98fe1dd3cce2c11c2ad8e145f2a44fe08ed28eb559"
dependencies = [
"diesel_derives",
"libsqlite3-sys",
"r2d2",
"time",
]
@ -1530,6 +1531,17 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "r2d2"
version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
dependencies = [
"log",
"parking_lot",
"scheduled-thread-pool",
]
[[package]]
name = "rand"
version = "0.8.5"
@ -1782,6 +1794,31 @@ dependencies = [
"uncased",
]
[[package]]
name = "rocket_sync_db_pools"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83f32721ed79509adac4328e97f817a8f55a47c4b64799f6fd6cc3adb6e42ff"
dependencies = [
"diesel",
"r2d2",
"rocket",
"rocket_sync_db_pools_codegen",
"serde",
"tokio",
"version_check",
]
[[package]]
name = "rocket_sync_db_pools_codegen"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc890925dc79370c28eb15c9957677093fdb7e8c44966d189f38cedb995ee68"
dependencies = [
"devise",
"quote",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -1869,6 +1906,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scheduled-thread-pool"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
dependencies = [
"parking_lot",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -1960,6 +2006,7 @@ dependencies = [
"reqwest",
"rocket",
"rocket-accept-language",
"rocket_sync_db_pools",
"serde",
"serde_json",
"tera",

View File

@ -34,6 +34,11 @@ version = "0.12"
default-features = false
features = ["rustls-tls", "socks"]
[dependencies.rocket_sync_db_pools]
version = "0.1"
default-features = false
features = ["diesel_sqlite_pool"]
[dependencies.tera]
version = "1.19"
default-features = false

View File

@ -4,8 +4,6 @@ pub mod schema;
use core::fmt::{Debug, Display, Formatter, Result};
use std::fs::read_to_string;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use kdl::KdlDocument;
pub struct Config {
@ -40,11 +38,6 @@ pub fn get_config() -> Config {
}
}
pub fn establish_connection() -> SqliteConnection {
SqliteConnection::establish(&get_config().database)
.unwrap_or_else(|_| panic!("Error connecting to database"))
}
#[derive(rocket::FromFormField, Debug, PartialEq)]
pub enum Software {
PeerTube,

View File

@ -3,7 +3,7 @@ extern crate rocket;
mod check;
use crate::check::check;
use services::{establish_connection, get_config, models::*, Software};
use services::{get_config, models::*, Config, Software};
use std::fs::File;
@ -12,6 +12,7 @@ use diesel::prelude::*;
use fluent_templates::FluentLoader;
use rocket::{
fairing::{Fairing, Info, Kind},
figment::{util::map, value::Value},
form::{self, Error, Form, Strict},
http::Header,
response::content::RawHtml,
@ -19,10 +20,11 @@ use rocket::{
Request, Response, State,
};
use rocket_accept_language::{language, AcceptLanguage, LanguageIdentifier};
use rocket_sync_db_pools::{database, diesel};
use serde::Serialize;
use serde_json::json;
use std::io::BufReader;
use tera::{Context, Tera, Value};
use tera::{Context, Tera};
use unic_langid::{langid, subtags::Language};
const LANGUAGE_DEFAULT: Language = language!("en");
@ -37,7 +39,7 @@ fluent_templates::static_loader! {
};
}
fn gen_context(accept_language: &AcceptLanguage, values: Value) -> Context {
fn gen_context(accept_language: &AcceptLanguage, values: tera::Value) -> Context {
let mut cont: Context = Context::from_value(json!({
"ln": &accept_language
.get_appropriate_language_region(&SL)
@ -66,37 +68,49 @@ impl Fairing for HttpHeaders {
}
}
#[database("main_db")]
struct DbConn(diesel::SqliteConnection);
#[launch]
fn rocket() -> _ {
let config = get_config();
let mut tera = Tera::new("templates/*.html.tera").unwrap();
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
let db: Database = Database::from_reader(BufReader::new(
File::open(get_config().ip_to_asn).expect("unable to open ip2asn TSV file"),
))
.unwrap();
rocket::build()
.manage(tera)
.manage(db)
.attach(Shield::new().enable(Referrer::NoReferrer))
.attach(HttpHeaders)
.mount(
"/",
routes![
list_services,
list_scans,
add_service_get,
add_service_post,
dl,
about,
],
)
rocket::custom(rocket::Config::figment().merge((
"databases",
map!["main_db" => map!{
"url" => Into::<Value>::into(config.database.clone()),
}],
)))
.manage(
Database::from_reader(BufReader::new(
File::open(&config.ip_to_asn).expect("unable to open ip2asn TSV file"),
))
.unwrap(),
)
.manage(config)
.manage(tera)
.attach(DbConn::fairing())
.attach(Shield::new().enable(Referrer::NoReferrer))
.attach(HttpHeaders)
.mount(
"/",
routes![
list_services,
list_scans,
add_service_get,
add_service_post,
dl,
about,
],
)
}
#[get("/services.db")]
fn dl() -> File {
File::open(get_config().database).unwrap()
fn dl(config: &State<Config>) -> File {
File::open(&config.database).unwrap()
}
#[derive(Serialize, Debug)]
@ -119,22 +133,27 @@ struct TemplateServices {
ip_info: Vec<IpInfo>,
}
#[get("/?<software>")]
fn list_services(
async fn list_services(
conn: DbConn,
tera: &State<Tera>,
db: &State<Database>,
ipdb: &State<Database>,
al: &AcceptLanguage,
software: Option<Strict<Software>>,
) -> RawHtml<String> {
let mut request = services::schema::services::dsl::services.into_boxed();
if let Some(s) = software {
request =
request.filter(services::schema::services::software.eq(s.to_string().to_lowercase()));
}
let services = request
.limit(300)
.select(Services::as_select())
.load(&mut establish_connection())
.unwrap();
let services = conn
.run(|c| {
let mut request = services::schema::services::dsl::services.into_boxed();
if let Some(s) = software {
request = request
.filter(services::schema::services::software.eq(s.to_string().to_lowercase()));
}
request
.limit(300)
.select(Services::as_select())
.load(c)
.unwrap()
})
.await;
let mut templates: Vec<TemplateServices> = vec![];
for service in &services {
@ -145,7 +164,7 @@ fn list_services(
.iter()
.filter(|ip| !ip.is_empty())
.for_each(|ip| {
match db.lookup(ip.parse().unwrap()).unwrap() {
match ipdb.lookup(ip.parse().unwrap()).unwrap() {
asn_db2::IpEntry::V6(info) => ip_info.push(IpInfo {
ip: ip.to_string(),
subnet: info.subnet.to_string(),
@ -190,18 +209,18 @@ fn list_services(
}
#[get("/list-scans")]
fn list_scans(tera: &State<Tera>, al: &AcceptLanguage) -> RawHtml<String> {
async fn list_scans(conn: DbConn, tera: &State<Tera>, al: &AcceptLanguage) -> RawHtml<String> {
RawHtml(
tera.render(
"list-scans.html.tera",
&gen_context(
al,
json!({
"scans": services::schema::scans::dsl::scans
.limit(1000)
.select(Scans::as_select())
.load(&mut establish_connection())
.unwrap()
"scans": conn.run(|c| services::schema::scans::dsl::scans
.limit(1000)
.select(Scans::as_select())
.load(c)
.unwrap()).await
}),
),
)
@ -242,6 +261,7 @@ struct Submission<'r> {
#[post("/add-service", data = "<submission>")]
async fn add_service_post(
conn: DbConn,
submission: Form<Strict<Submission<'_>>>,
tera: &State<Tera>,
al: &AcceptLanguage,
@ -262,20 +282,23 @@ async fn add_service_post(
}
};
diesel::insert_into(services::table())
.values(Services {
url: service.url,
software: service.software,
server: service.server,
ipv6: "".to_string(),
ipv4: "".to_string(),
availability_ipv6: "".to_string(),
availability_ipv4: "".to_string(),
address_ipv6: "".to_string(),
address_ipv4: "".to_string(),
})
.execute(&mut establish_connection())
.unwrap();
conn.run(|c| {
diesel::insert_into(services::table())
.values(Services {
url: service.url,
software: service.software,
server: service.server,
ipv6: "".to_string(),
ipv4: "".to_string(),
availability_ipv6: "".to_string(),
availability_ipv4: "".to_string(),
address_ipv6: "".to_string(),
address_ipv4: "".to_string(),
})
.execute(c)
.unwrap()
})
.await;
RawHtml(
tera.render("add-service.html.tera", &gen_context(al, json!({})))
@ -284,14 +307,14 @@ async fn add_service_post(
}
#[get("/about")]
fn about(tera: &State<Tera>, al: &AcceptLanguage) -> RawHtml<String> {
fn about(config: &State<Config>, tera: &State<Tera>, al: &AcceptLanguage) -> RawHtml<String> {
RawHtml(
tera.render(
"about.html.tera",
&gen_context(
al,
json!({
"source_code": get_config().source_code,
"source_code": config.source_code,
}),
),
)

View File

@ -1,28 +1,32 @@
mod check;
use crate::check::check;
use ::services::establish_connection;
use ::services::models::Scans;
use ::services::models::Services;
use ::services::schema::scans::dsl::scans;
use ::services::schema::scans::installation;
use ::services::schema::services::dsl::*;
use diesel::associations::HasTable;
use diesel::ExpressionMethods;
use diesel::QueryDsl;
use diesel::RunQueryDsl;
use diesel::SelectableHelper;
use dns_lookup::lookup_host;
use ::services::{
get_config,
models::{Scans, Services},
schema::{
scans::{dsl::scans, installation},
services::dsl::*,
},
};
use std::net::IpAddr;
use diesel::{
associations::HasTable, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper,
SqliteConnection,
};
use dns_lookup::lookup_host;
#[tokio::main]
async fn main() {
let connection = &mut establish_connection();
let config = get_config();
let mut conn = SqliteConnection::establish(&config.database)
.unwrap_or_else(|_| panic!("Error connecting to database"));
for service in services
.limit(300)
.select(Services::as_select())
.load(connection)
.load(&mut conn)
.expect("Error loading services")
{
let result_ipv6 = match check(&service.url, Some(6)).await {
@ -46,14 +50,14 @@ async fn main() {
result_ipv6: result_ipv6.clone(),
result_ipv4: result_ipv4.clone(),
})
.execute(connection)
.execute(&mut conn)
.unwrap();
let installation_scans = scans
.filter(installation.eq(service.url.to_string()))
.limit(100)
.select(Scans::as_select())
.load(connection)
.load(&mut conn)
.unwrap();
let ipv6_successes = installation_scans
@ -99,7 +103,7 @@ async fn main() {
address_ipv6.eq(&addr_ipv6.join(",")),
address_ipv4.eq(&addr_ipv4.join(",")),
))
.execute(connection)
.execute(&mut conn)
.unwrap();
}
}