extern crate diesel; #[macro_use] extern crate diesel_migrations; use std::env; use std::collections::HashSet; use std::sync::Arc; use log::{error, warn, info}; use serenity::client::Cache; use serenity::framework::StandardFramework; use serenity::http::Http; use serenity::prelude::*; use songbird::{SerenityInit, Songbird}; use actix_cors::Cors; use actix_web::{HttpServer, App, web}; use crate::bot::{commands::oai::GPTModel, handler::Handler}; use dotenv::dotenv; mod auth; mod dnd; mod bot; mod storage; mod users; #[actix_web::main] async fn main() -> std::io::Result<()> { dotenv().ok(); env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,siren=info")); storage::init().await; match env::var("DATA_DIR_PATH") { Ok(data_dir_path) => dnd::load_data(&data_dir_path), Err(err) => warn!("Unable to load initial database data: {}", err) }; let token: String = env::var("DISCORD_TOKEN").expect("Expected a token in the environment"); let intents: GatewayIntents = GatewayIntents::all(); let http: Http = Http::new(&token); let (owners, _bot_id) = match http.get_current_application_info().await { Ok(info) => { let mut owners: HashSet = HashSet::new(); if let Some(team) = info.team { owners.insert(team.owner_user_id); } else { owners.insert(info.owner.id); } match http.get_current_user().await { Ok(bot) => (owners, bot.id), Err(why) => panic!("Could not access the bot id: {:?}", why) } }, Err(why) => panic!("Could not access application info: {:?}", why) }; let handler = match env::var("OPENAI_API_KEY") { Ok(token) => { info!("Loaded OpenAI token"); Handler { oai: Some(bot::commands::oai::OAI { client: reqwest::Client::new(), base_url: "https://api.openai.com/v1".to_string(), service_url: "http://localhost:5000".to_string(), max_attempts: 5, token, max_context_questions: 30, max_tokens: 2048, default_model: GPTModel::GPT35Turbo, }) } } Err(err) => { warn!("Could not load OpenAI token: {}", err); Handler { oai: None } } }; let songbird = Songbird::serenity(); let mut client = Client::builder(token, intents) .event_handler(handler) .framework(StandardFramework::new() .configure(|c| c.owners(owners))) .register_songbird_with(Arc::clone(&songbird)) .await .expect("Error creating client"); let http = Arc::clone(&client.cache_and_http.http); let cache = Arc::clone(&client.cache_and_http.cache); let app_data = Arc::new(AppState { http, cache, songbird: Arc::clone(&songbird) }); let shard_manager = Arc::clone(&client.shard_manager); // tokio::spawn(async move { // tokio::signal::ctrl_c().await.expect("Could not register ctrl+c handler"); // shard_manager.lock().await.shutdown_all().await; // }); // tokio::spawn(async move { // if let Err(why) = client.start_autosharded().await { // error!("An error occurred while running the client: {:?}", why); // } // }); let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string()); let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string()); let server = match HttpServer::new(move || { let cors = Cors::default() .allow_any_origin() .allow_any_method() .allow_any_header() .supports_credentials() .max_age(3600); App::new() .wrap(cors) .app_data(web::Data::new(Arc::clone(&app_data))) .configure(crate::storage::messages::init_routes) .configure(crate::auth::init_routes) .configure(crate::users::init_routes) .configure(crate::dnd::spells::init_routes) .configure(crate::bot::api::init_routes) }) .bind(format!("{}:{}", host, port)) { Ok(b) => { info!("Binding server to {}:{}", host, port); b }, Err(err) => { error!("Could not bind server: {}", err); return Err(err); } }; server.run() .await } pub struct AppState { pub http: Arc, pub cache: Arc, pub songbird: Arc }