use crate::config::GlobalData; use crate::discord::voices::speak; use crate::models::api_key::Apikey; use axum::extract::State; use axum::{Json, Router, http::StatusCode, response::IntoResponse, routing::post}; use log::info; use serde::Deserialize; use std::sync::Arc; #[derive(Clone)] struct ApiContext { data: Arc, ctx: poise::serenity_prelude::Context, } pub async fn web_server(data: Arc, ctx: poise::serenity_prelude::Context) { let addr = data.cfg.api_addr; let app = Router::new() .route("/play", post(play_sound)) .with_state(ApiContext { data, ctx }); info!("Serving bot api on: {}", addr); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); } #[derive(Deserialize)] struct SoundPayload { pub api_key: String, pub voice: String, pub phrase: String, } async fn play_sound( State(ctx): State, Json(payload): Json, ) -> impl IntoResponse { if let Some(api_key) = Apikey::find_key_from_secret(&ctx.data.db, &payload.api_key).unwrap() && let Some(user_id) = api_key.user_id { info!("Playing audio for {user_id}"); speak( &ctx.ctx, &ctx.data, ctx.data.cfg.guild_id, user_id, &payload.voice, &payload.phrase, ) .await .unwrap(); } StatusCode::ACCEPTED }