use skynet_discord_bot::{db_init, get_config, get_server_config_bulk, Accounts, Config, DataBase, Servers}; use std::{process, sync::Arc}; use serde::Deserialize; use serenity::{ async_trait, client::{Context, EventHandler}, model::{ gateway::{GatewayIntents, Ready}, id::GuildId, }, Client, }; use sqlx::{Pool, Sqlite}; use tokio::sync::RwLock; #[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))); } // Finally, start a single shard, and start listening to events. // // Shards will automatically attempt to reconnect, and will perform // exponential backoff until it reconnects. 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) { println!("{} is connected!", ready.user.name); fetch_accounts(&ctx).await; process::exit(0); } } async fn fetch_accounts(ctx: &Context) { let config_lock = { let data_read = ctx.data.read().await; data_read.get::().expect("Expected Config in TypeMap.").clone() }; let config = config_lock.read().await; 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; // handle wolves api here get_wolves(&db).await; // get from skynet for the compsoc server only get_skynet(&db, &config).await; } #[derive(Debug, Deserialize)] pub struct SkynetResult { discord: String, id_wolves: String, id_member: String, } async fn get_skynet(db: &Pool, config: &Config) { let url = format!("{}/ldap/discord?auth={}", &config.ldap_api, &config.auth); if let Ok(result) = surf::get(url).recv_json::>().await { for user in result { add_users_skynet(db, &config.skynet_server, &user).await; } } } async fn add_users_skynet(db: &Pool, server: &GuildId, user: &SkynetResult) { if !user.id_wolves.is_empty() { match sqlx::query_as::<_, Accounts>( " UPDATE accounts SET discord = ? WHERE server = ? AND wolves_id = ? ", ) .bind(&user.discord) .bind(*server.as_u64() as i64) .bind(&user.id_wolves) .fetch_optional(db) .await { Ok(_) => {} Err(e) => { println!("Failure to insert into {} {:?}", server.as_u64(), user); println!("{:?}", e); } } } if !user.id_member.is_empty() { match sqlx::query_as::<_, Accounts>( " UPDATE accounts SET discord = ? WHERE server = ? AND id_member = ? ", ) .bind(&user.discord) .bind(*server.as_u64() as i64) .bind(&user.id_member) .fetch_optional(db) .await { Ok(_) => {} Err(e) => { println!("Failure to insert into {} {:?}", server.as_u64(), user); println!("{:?}", e); } } } } #[derive(Debug, Deserialize)] struct WolvesResult { pub id_wolves: String, pub email: String, pub expiry: String, } async fn get_wolves(db: &Pool) { for server_config in get_server_config_bulk(db).await { let Servers { server, wolves_api, .. } = server_config; // get the data here let result: Vec = vec![]; for user in result { add_users_wolves(db, &server, &user).await; } } } async fn add_users_wolves(db: &Pool, server: &GuildId, user: &WolvesResult) { match sqlx::query_as::<_, Accounts>( " INSERT OR REPLACE INTO accounts (server, id_wolves, email, expiry) VALUES (?1, ?2, ?3, ?4) ", ) .bind(*server.as_u64() as i64) .bind(&user.id_wolves) .bind(&user.email) .bind(&user.expiry) .fetch_optional(db) .await { Ok(_) => {} Err(e) => { println!("Failure to insert into {} {:?}", server.as_u64(), user); println!("{:?}", e); } } }