root/src/main.rs

// main.rs
//
// Copyright 2020-2024 nee <nee-git@hidamari.blue>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#[macro_use]
extern crate tracing;

mod application;
#[rustfmt::skip]
mod config;
mod booru;
mod browse_page;
mod data;
mod download;
mod image_page;
mod saved_searches_sidebar;
mod settings;
mod settings_data;
mod sidebar_booru_select;
mod thumb;
mod wiki_page;
mod window;

use gettextrs::{LocaleCategory, gettext};
use gtk::{gio, glib};
use once_cell::sync::Lazy;
pub use settings_data::DEFAULT_THUMB_SIZE_IMAGE;
pub use settings_data::DEFAULT_THUMB_SIZE_UI;
use sqlx::migrate::Migrator;
use std::sync::LazyLock;

use self::application::ExampleApplication;
use self::config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE};

// tokio should be used when doing http fetches, since reqwest depens on it.
pub static RUNTIME: Lazy<tokio::runtime::Runtime> =
    Lazy::new(|| tokio::runtime::Runtime::new().unwrap());

static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations"

pub static POOL: LazyLock<sqlx::SqlitePool> = LazyLock::new(|| RUNTIME.block_on(init_db()));

fn main() -> glib::ExitCode {
    // Initialize logger
    tracing_subscriber::fmt::init();

    // Prepare i18n
    gettextrs::setlocale(LocaleCategory::LcAll, "");
    gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
    gettextrs::textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");

    glib::set_application_name(&gettext("Boorus"));

    let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file");
    gio::resources_register(&res);

    let _ = POOL.clone(); // init the db

    // uncomment to easily get hash for any new domain to implement
    // use std::collections::HashMap;
    // use std::hash::Hasher;
    // let mut hasher = std::collections::hash_map::DefaultHasher::new();
    // hasher.write("__builtin_localbooru".as_bytes());
    // let hash = hasher.finish();
    // println!("HASH {}", hash);

    let app = ExampleApplication::default();
    app.run()
}

async fn init_db() -> sqlx::SqlitePool {
    use sqlx::sqlite::*;
    let mut path = gtk::glib::user_config_dir();
    path.push("boorus");
    if let Err(e) = std::fs::create_dir_all(&path) {
        error!("failed to create settings dir, during sql pool init: {e}");
    }
    path.push("db.db");

    println!("PATH {}", path.display());

    let pool = SqlitePool::connect_with(
        SqliteConnectOptions::new()
            .filename(path)
            .create_if_missing(true),
    )
    .await
    .expect("failed to create db");

    MIGRATOR
        .run(&pool)
        .await
        .expect("Error running DB migrations");

    pool
}