|
- #![feature(proc_macro_hygiene, decl_macro)]
-
- mod auth_tools;
- mod discord;
- mod command_definitions;
-
- #[macro_use] extern crate rocket;
- use lazy_static::lazy_static;
-
- use rocket_contrib::json::Json;
- use std::sync::RwLock;
- use crate::auth_tools::{AuthenticatedInteraction};
- use crate::discord::{InteractionResponse, InteractionApplicationCommandCallbackData, ApplicationCommand};
- use crate::command_definitions::hello_world;
- use std::collections::{HashMap, HashSet};
-
- static GLOBAL_COMMAND_KEY: &str = "GLOBAL command KEY";
-
- lazy_static! {
- pub static ref VERIFICATION_KEY: RwLock<Option<ed25519_dalek::PublicKey>> = RwLock::new(None);
- pub static ref APPLICATION_ID: RwLock<Option<String>> = RwLock::new(None);
- pub static ref BOT_TOKEN: RwLock<Option<String>> = RwLock::new(None);
- }
-
- #[post("/", data = "<interaction>")]
- fn root_post(interaction: AuthenticatedInteraction) -> Json<InteractionResponse> {
- if interaction.interaction.is_ping() {
- return Json(InteractionResponse::Pong {})
- }
- let resp = InteractionResponse::ChannelMessage {
- data: Some(InteractionApplicationCommandCallbackData {
- tts: false,
- content: "Hello".to_string(),
- allowed_mentions: None,
- }),
- };
- Json(resp)
- }
-
- #[get("/")]
- fn hello_get() -> &'static str {
- "Hello, why are you here?"
- }
-
- fn main() {
- // Init verification key
- let public_key = std::env::var("DISCORD_PUBLIC_KEY")
- .expect("Environment variable DISCORD_PUBLIC_KEY not found");
- println!("Discord Pub Key {}", &public_key);
- *VERIFICATION_KEY.write().unwrap() = Some(ed25519_dalek::PublicKey::from_bytes(
- &hex::decode(public_key)
- .expect("Invalid hex string")).expect("Invalid public key"));
- // get application ID for sending API requests
- let app_id = std::env::var("DISCORD_APP_ID")
- .expect("Environment variable DISCORD_APP_ID not found");
- println!("Discord App Id {}", &app_id);
- *APPLICATION_ID.write().unwrap() = Some(app_id.to_string());
- // get bot token for sending API requests
- let token = std::env::var("DISCORD_TOKEN")
- .expect("Environment variable DISCORD_TOKEN not found");
- println!("Discord App Id {}", &app_id);
- *BOT_TOKEN.write().unwrap() = Some(token.to_string());
-
- // send API requests to bootstrap commands
- let req_client = reqwest::blocking::Client::new();
- let mut seen_cmds = HashMap::<String, HashSet<String>>::new();
- // TODO
- register_command(&hello_world, &req_client, &mut seen_cmds);
- // start web server
- rocket::ignite().mount("/", routes![root_post, hello_get]).launch();
- }
-
- fn register_command(f: &dyn Fn() -> (discord::ApplicationCommand, Option<String>),
- client: &reqwest::blocking::Client,
- registered: &mut HashMap<String, HashSet<String>>) {
- let (payload, guild_opt) = f();
- if let Some(guild_id) = guild_opt {
- if !registered.contains_key(&guild_id) {
- let mut seen_guild_cmds = HashSet::new();
- let cmds = get_guild_commands(client, &guild_id);
- for c in cmds {
- println!("Found app command {} ID:{} App:{}", &c.name, &c.id.unwrap(), guild_id);
- seen_guild_cmds.insert(c.name);
- }
- registered.insert(guild_id.clone(), seen_guild_cmds);
- }
- if !registered.get(&guild_id).unwrap().contains(&payload.name) {
- // create new command
- let url = format!("https://discord.com/api/v8/applications/{}/guilds/{}/commands", APPLICATION_ID.read().unwrap().as_ref().unwrap().clone(), &guild_id);
- let res = client.post(&url)
- .header("Authorization", format!("Bot {}", BOT_TOKEN.read().unwrap().as_ref().unwrap().clone()))
- .json(&payload)
- .send();
- if let Ok(d) = res {
- println!("`{}` status {}", &payload.name, &d.status().as_str());
- println!("{}", &d.text().unwrap());
- registered.get_mut(&guild_id).unwrap().insert(payload.name);
- }
- }
- } else {
- if !registered.contains_key(GLOBAL_COMMAND_KEY) {
- let mut seen_cmds = HashSet::new();
- let cmds = get_commands(client);
- for c in cmds {
- println!("Found global command {} ID:{}", &c.name, &c.id.unwrap());
- seen_cmds.insert(c.name);
- }
- registered.insert(GLOBAL_COMMAND_KEY.to_string(), seen_cmds);
- }
- if !registered.get(GLOBAL_COMMAND_KEY).unwrap().contains(&payload.name) {
- // create new command
- let url = format!("https://discord.com/api/v8/applications/{}/commands", APPLICATION_ID.read().unwrap().as_ref().unwrap().clone());
- let res = client.post(&url)
- .header("Authorization", format!("Bot {}", BOT_TOKEN.read().unwrap().as_ref().unwrap().clone()))
- .json(&payload)
- .send();
- if let Ok(d) = res {
- println!("`{}` status {}", &payload.name, &d.status().as_str());
- println!("{}", &d.text().unwrap());
- registered.get_mut(GLOBAL_COMMAND_KEY.clone()).unwrap().insert(payload.name);
- }
- }
-
- }
- }
-
- fn get_commands(client: &reqwest::blocking::Client) -> Vec<ApplicationCommand> {
- let url = format!("https://discord.com/api/v8/applications/{}/commands", APPLICATION_ID.read().unwrap().as_ref().unwrap().clone());
- let res = client.get(&url)
- .header("Authorization", format!("Bot {}", BOT_TOKEN.read().unwrap().as_ref().unwrap().clone()))
- .send();
- if let Ok(d) = res {
- println!("Commands GET status {}", &d.status().as_str());
- return d.json().unwrap();
- }
- return Vec::new();
- }
-
- fn get_guild_commands(client: &reqwest::blocking::Client, guild_id: &str) -> Vec<ApplicationCommand> {
- let url = format!("https://discord.com/api/v8/applications/{}/guilds/{}/commands", APPLICATION_ID.read().unwrap().as_ref().unwrap().clone(), guild_id);
- let res = client.get(&url)
- .header("Authorization", format!("Bot {}", BOT_TOKEN.read().unwrap().as_ref().unwrap().clone()))
- .send();
- if let Ok(d) = res {
- println!("Commands GET status {}", &d.status().as_str());
- return d.json().unwrap();
- }
- return Vec::new();
- }
|