initial commit
This commit is contained in:
commit
4bb3879443
5 changed files with 2538 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
.env
|
2374
Cargo.lock
generated
Normal file
2374
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "gork"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dotenvy = "0.15.7"
|
||||||
|
rand = "0.9.1"
|
||||||
|
serenity = "0.12"
|
||||||
|
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
||||||
|
yaml-rust2 = "0.10.1"
|
26
config.yaml
Normal file
26
config.yaml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
questions:
|
||||||
|
- "?"
|
||||||
|
- should
|
||||||
|
- will
|
||||||
|
- is
|
||||||
|
- gonna
|
||||||
|
- going to
|
||||||
|
- do
|
||||||
|
- are
|
||||||
|
default_responses:
|
||||||
|
- no
|
||||||
|
- don't think so
|
||||||
|
- nah
|
||||||
|
- definitely
|
||||||
|
- nope
|
||||||
|
question_responses:
|
||||||
|
- yes
|
||||||
|
- idk
|
||||||
|
- maybe
|
||||||
|
- for sure
|
||||||
|
- i hope so
|
||||||
|
- hopefully not
|
||||||
|
- probably not
|
||||||
|
- probably
|
||||||
|
- yep
|
||||||
|
- certainly
|
125
src/main.rs
Normal file
125
src/main.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use std::env;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use dotenvy::dotenv;
|
||||||
|
use rand::random_range;
|
||||||
|
use rand::seq::IndexedRandom;
|
||||||
|
use serenity::all::Typing;
|
||||||
|
use serenity::async_trait;
|
||||||
|
use serenity::model::channel::Message;
|
||||||
|
use serenity::prelude::*;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
use yaml_rust2::{Yaml, YamlLoader};
|
||||||
|
|
||||||
|
fn is_question(message: &str) -> bool {
|
||||||
|
get_keywords()
|
||||||
|
.questions
|
||||||
|
.iter()
|
||||||
|
.any(|keyword| message.contains(keyword))
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Keywords {
|
||||||
|
questions: Vec<String>,
|
||||||
|
default_responses: Vec<String>,
|
||||||
|
question_responses: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_keywords() -> Keywords {
|
||||||
|
let mut docs: Vec<Yaml> =
|
||||||
|
YamlLoader::load_from_str(&read_to_string("config.yaml").expect("Need a config.yaml"))
|
||||||
|
.expect("Invalid yaml! Could not parse.");
|
||||||
|
|
||||||
|
let config: &mut Yaml = docs
|
||||||
|
.get_mut(0) // This returns Option<&mut Yaml>
|
||||||
|
.expect("Invalid yaml! No documents found in YAML file.");
|
||||||
|
|
||||||
|
// Your closure now works because `config` is `&mut Yaml`
|
||||||
|
let mut load_array = |key: &str| {
|
||||||
|
config[key] // This will use IndexMut if config is &mut Yaml, giving &mut Yaml
|
||||||
|
.as_mut_vec() // Requires &mut self on the Yaml item
|
||||||
|
.expect(&format!("Invalid or missing array for key: '{}'", key))
|
||||||
|
.into_iter() // Iterates over &mut Yaml items in the inner vec
|
||||||
|
.map(|x| {
|
||||||
|
x.as_str()
|
||||||
|
.expect(&format!(
|
||||||
|
"Non-string value found in array for key: '{}'",
|
||||||
|
key
|
||||||
|
))
|
||||||
|
.to_string() // Convert &str to owned String
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
Keywords {
|
||||||
|
questions: load_array("questions"),
|
||||||
|
default_responses: load_array("default_responses"),
|
||||||
|
question_responses: load_array("question_responses"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Handler;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventHandler for Handler {
|
||||||
|
async fn message(&self, ctx: Context, msg: Message) {
|
||||||
|
let mut responses = get_keywords().default_responses;
|
||||||
|
|
||||||
|
if is_question(&msg.content) {
|
||||||
|
responses.extend(get_keywords().question_responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_user_id = match ctx.http.get_current_user().await {
|
||||||
|
Ok(user) => user.id,
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Could not get current user: {:?}", why);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !msg.mentions.iter().any(|user| user.id == current_user_id)
|
||||||
|
|| msg.referenced_message.is_some()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let typing = Typing::start(ctx.http.clone(), msg.channel_id);
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(random_range(600..2200))).await;
|
||||||
|
|
||||||
|
let selected_response = {
|
||||||
|
let mut rng_instance = rand::rng();
|
||||||
|
responses
|
||||||
|
.choose(&mut rng_instance)
|
||||||
|
.expect("Responses array should not be empty")
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(why) = msg.channel_id.say(&ctx.http, selected_response).await {
|
||||||
|
eprintln!("Error sending message: {:?}", why);
|
||||||
|
}
|
||||||
|
|
||||||
|
typing.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
dotenv().expect("Need a .env file!");
|
||||||
|
// Login with a bot token from the environment
|
||||||
|
let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
|
||||||
|
// Set gateway intents, which decides what events the bot will be notified about
|
||||||
|
let intents = GatewayIntents::GUILD_MESSAGES
|
||||||
|
| GatewayIntents::DIRECT_MESSAGES
|
||||||
|
| GatewayIntents::MESSAGE_CONTENT;
|
||||||
|
|
||||||
|
// Create a new instance of the Client, logging in as a bot.
|
||||||
|
let mut client = Client::builder(&token, intents)
|
||||||
|
.event_handler(Handler)
|
||||||
|
.await
|
||||||
|
.expect("Err creating client");
|
||||||
|
|
||||||
|
// Start listening for events by starting a single shard
|
||||||
|
if let Err(why) = client.start().await {
|
||||||
|
println!("Client error: {why:?}");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue