Re-implementing the API

This commit is contained in:
2024-12-19 13:50:31 -05:00
parent 9344979d72
commit 4a18af9014
17 changed files with 486 additions and 152 deletions

View File

@@ -1,15 +1,13 @@
use std::env;
use std::collections::HashSet;
use std::sync::Arc;
use axum::Router;
use serenity::http::Http;
use serenity::prelude::*;
use songbird::{SerenityInit, Songbird};
use reqwest::Client as HttpClient;
use serenity::all::{ShardManager, UserId};
use tokio::net::TcpListener;
use crate::bot::handler::Handler;
use serenity::all::{Cache, ShardManager, UserId};
use crate::api::App;
use crate::bot::handler::BotHandler;
use crate::bot::oai::OAI;
mod api;
@@ -24,47 +22,24 @@ impl TypeMapKey for HttpKey {
type Value = HttpClient;
}
#[derive(Clone)]
struct AppState {
client: reqwest::Client,
client_id: String,
client_secret: String,
redirect_uri: String,
http: Arc<Http>,
cache: Arc<Cache>,
}
#[tokio::main]
async fn main() {
async fn main() -> Result<(), Box<dyn std::error::Error>> {
dotenv::dotenv().ok();
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,siren=info"));
if let Err(err) = data::initialize().await {
log::error!("Failed to initialize database: {err}");
return;
};
data::initialize().await?;
// Start API server
tokio::spawn(start_api());
// Start Discord bot
start_bot().await;
}
async fn start_api() {
let app = Router::new();
let addr: String = "127.0.0.1:3000".parse().unwrap();
let listener = TcpListener::bind(&addr).await.unwrap();
log::debug!("API is listening on {}", &addr);
axum::serve(listener, app).await.unwrap();
}
async fn start_bot() {
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) = get_bot_info(&http).await;
log::debug!(
"Starting Discord bot with ID: {bot_id} and owners: {}",
owners
.iter()
.map(|id| id.to_string())
.collect::<Vec<_>>()
.join(", ")
);
// Set up handler with optional OpenAI integration
let handler = configure_handler();
@@ -72,6 +47,8 @@ async fn start_bot() {
// Set up Songbird for voice functionality
let songbird = Songbird::serenity();
let intents: GatewayIntents = GatewayIntents::all();
let mut client = Client::builder(token, intents)
.event_handler(handler)
// .framework(StandardFramework::new().configure(|c| c.owners(owners)))
@@ -80,29 +57,53 @@ async fn start_bot() {
.await
.expect("Error creating client");
let (bot_owner, bot_id) = get_bot_info(&client.http).await;
let client_secret: String =
env::var("DISCORD_SECRET").expect("Expected a secret in the environment");
let redirect_uri: String =
env::var("API_CALLBACK_URI").expect("Expected a secret in the environment");
let app_state = AppState {
client: HttpClient::new(),
client_id: bot_id.to_string(),
client_secret,
redirect_uri,
http: Arc::clone(&client.http),
cache: Arc::clone(&client.cache),
};
log::debug!("Starting Siren with ID: {bot_id} (Contact: {:?})", bot_owner);
// Spawn shutdown signal handling
let shard_manager = Arc::clone(&client.shard_manager);
tokio::spawn(async move {
signal_shutdown(shard_manager).await;
});
// Start the bot
// Start API server
tokio::spawn(App::new(app_state).serve());
// Start Discord bot
if let Err(why) = client.start_autosharded().await {
log::error!("Client error: {why:?}");
}
Ok(())
}
async fn get_bot_info(http: &Http) -> (HashSet<UserId>, UserId) {
async fn get_bot_info(http: &Http) -> (Option<UserId>, UserId) {
match http.get_current_application_info().await {
Ok(info) => {
let mut owners = HashSet::new();
let bot_owner;
if let Some(team) = info.team {
owners.insert(team.owner_user_id);
bot_owner = Some(team.owner_user_id);
} else if let Some(owner) = info.owner {
owners.insert(owner.id);
bot_owner = Some(owner.id);
} else {
bot_owner = None;
}
match http.get_current_user().await {
Ok(bot) => (owners, bot.id),
Ok(bot) => (bot_owner, bot.id),
Err(why) => panic!("Could not access the bot id: {why:?}"),
}
}
@@ -110,13 +111,13 @@ async fn get_bot_info(http: &Http) -> (HashSet<UserId>, UserId) {
}
}
fn configure_handler() -> Handler {
fn configure_handler() -> BotHandler {
match env::var("OPENAI_TOKEN") {
Ok(token) => {
log::debug!("OpenAI functionality enabled");
let default_model = env::var("OPENAI_MODEL").unwrap_or_else(|_| "gpt-4o-mini".to_string());
let base_url = env::var("OPENAI_BASE_URL").unwrap();
Handler {
BotHandler {
oai: Some(OAI {
client: reqwest::Client::new(),
base_url,
@@ -129,7 +130,7 @@ fn configure_handler() -> Handler {
}
Err(_) => {
log::warn!("OpenAI functionality disabled");
Handler { oai: None }
BotHandler { oai: None }
}
}
}