use serenity::{ async_trait, client::{Context, EventHandler}, model::gateway::{GatewayIntents, Ready}, Client, }; use skynet_discord_bot::common::database::{db_init, DataBase}; use skynet_discord_bot::{get_config, Config}; use std::{fs, process, sync::Arc}; use std::ffi::OsStr; use std::fs::File; use std::io::Read; use std::path::PathBuf; use std::process::Command; use chrono::{Datelike, Utc}; use gdk_pixbuf::{Pixbuf, PixbufFormat, PixbufLoader}; use gdk_pixbuf::prelude::PixbufLoaderExt; use resvg::usvg; use serde::Deserialize; use serenity::all::GuildId; use tokio::sync::RwLock; use skynet_discord_bot::common::renderer::{Args, Renderer}; #[tokio::main] async fn main() { let config = get_config(); let db = match db_init(&config).await { Ok(x) => x, Err(_) => return, }; // Intents are a bitflag, bitwise operations can be used to dictate which intents to use let intents = GatewayIntents::GUILDS | GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS; // Build our client. let mut client = Client::builder(&config.discord_token, intents) .event_handler(Handler {}) .await .expect("Error creating client"); { let mut data = client.data.write().await; data.insert::(Arc::new(RwLock::new(config))); data.insert::(Arc::new(RwLock::new(db))); } if let Err(why) = client.start().await { println!("Client error: {:?}", why); } } struct Handler; #[async_trait] impl EventHandler for Handler { async fn ready(&self, ctx: Context, ready: Ready) { let ctx = Arc::new(ctx); println!("{} is connected!", ready.user.name); // pull in the open governance repo // u[date committee server update_icon_main(Arc::clone(&ctx)).await; // finish up process::exit(0); } } async fn update_icon_main(ctx: Arc) { let db_lock = { let data_read = ctx.data.read().await; data_read.get::().expect("Expected Config in TypeMap.").clone() }; let db = db_lock.read().await; let config_lock = { let data_read = ctx.data.read().await; data_read.get::().expect("Expected Config in TypeMap.").clone() }; let config_global = config_lock.read().await; let config_toml = get_config_icons(); let server = GuildId::new(689189992417067052); // clone repo into local folder clone_repo(&config_global, &config_toml); // see if there is a current festival let festival_data = get_festival(&config_toml); // get a list of all the graphics files get_logos(&config_global, &config_toml); } fn get_festival(config_toml: &ConfigToml)-> (Option, Vec){ let today = Utc::now(); let day = today.day(); let month = today.month(); let year = today.year(); let mut festival_current = None; let mut festival_not = vec![]; for festival in &config_toml.festivals { if (day >= festival.start.day && day <= festival.end.day) && (month >= festival.start.month && month <= festival.end.month ) && (year >= festival.start.year && year <= festival.end.year) { festival_current = Some(festival.name.to_owned()); } else if !festival.all_year { festival_not.push(festival.name.to_owned()); } } (festival_current, festival_not) } #[derive(Deserialize)] struct ConfigToml { source: ConfigTomlSource, festivals: Vec, } #[derive(Deserialize)] struct ConfigTomlSource { repo: String, directory: String, } #[derive(Deserialize)] struct ConfigTomlFestivals { name: String, all_year: bool, start: ConfigTomlFestivalsTime, end: ConfigTomlFestivalsTime, } #[derive(Deserialize)] struct ConfigTomlFestivalsTime { day: u32, month: u32, year:i32 } fn get_config_icons() -> ConfigToml { let toml_raw = include_str!("../../.server-icons.toml"); let config: ConfigToml = toml::from_str(toml_raw).unwrap(); config } fn clone_repo(config: &Config, config_toml: &ConfigToml){ let url = &config_toml.source.repo; let folder = format!("{}/open-governance", &config.home); Command::new("git") .arg("clone") .arg(url) .arg(&folder) .output() .expect("failed to execute process"); Command::new("git") .arg("pull") .arg("origin") .arg("main") .current_dir(&folder) .output() .expect("failed to execute process"); } fn convert_svg_to_png(original: &PathBuf, out: &PathBuf){ let mut f = File::open(original).unwrap(); let mut buffer = Vec::new(); // read the whole file f.read_to_end(&mut buffer).unwrap(); let loader = PixbufLoader::with_mime_type("image/svg+xml") .expect("error loader"); loader.write(&buffer).expect("TODO: panic message"); loader.close().expect("TODO: panic message"); let pixbuf = loader.pixbuf().expect("no pixbuf"); let (width, height) = (pixbuf.width(), pixbuf.height()); println!("size: {}x{}", width, height); let bytes: Vec = pixbuf.save_to_bufferv("png", &[]).expect("must not error"); fs::write(out, &bytes).expect("TODO: panic message"); } fn get_logos(config: &Config, config_toml: &ConfigToml){ let folder = format!("{}/open-governance/{}", &config.home, &config_toml.source.directory); let folder_path = PathBuf::from(&folder); let paths = fs::read_dir(folder).unwrap(); let args = Args{ input: folder_path.clone(), output: folder_path.clone(), colors: String::from(""), width: 1024, height: 1024, }; let mut r = Renderer::new(&args).unwrap(); for path in paths { let tmp = path.unwrap(); let mut path_local = tmp.path().to_owned(); match tmp.path().extension() { None => {} Some(ext) => { if ext == "svg" { let mut path_new = path_local.clone(); path_new.set_extension("png"); // check if exists match r.render(&path_local, &args) { Ok(_) => log::info!("Successfully rendered all colors of {path_local:?}"), Err(e) => { log::error!("Failed to render {path_local:?}: {}", e) } } path_local = path_new; } } }; println!("Name: {}", &tmp.path().display()); } }