Initial Commit
This commit is contained in:
commit
3172a07b38
|
@ -0,0 +1,6 @@
|
|||
/target
|
||||
.env
|
||||
*.yaml
|
||||
!example_config.yaml
|
||||
/data
|
||||
*.log
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "whisper_wolf_3"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serenity = { version = "0.11", features = ["builder", "cache", "collector", "client", "utils", "rustls_backend", "model"], default-features = false }
|
||||
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
|
||||
poise = "0.5"
|
||||
chrono = "0.4"
|
||||
once_cell = "1.18"
|
||||
serde = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
diesel = { version = "2.1", features = ["sqlite"] }
|
|
@ -0,0 +1,6 @@
|
|||
token: ""
|
||||
log_dir: "logs"
|
||||
hash_ids: true
|
||||
channel: 0
|
||||
admins:
|
||||
- 0
|
|
@ -0,0 +1,5 @@
|
|||
pub mod notify;
|
||||
|
||||
pub struct Data {}
|
||||
type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||
type Context<'a> = poise::Context<'a, Data, Error>;
|
|
@ -0,0 +1,11 @@
|
|||
use super::{Error, Context};
|
||||
|
||||
#[poise::command(slash_command, prefix_command, dm_only)]
|
||||
pub async fn notify(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Turn notifications on or off"] toggle: bool,
|
||||
) -> Result<(), Error> {
|
||||
let response = format!("Notifications are now {}", toggle);
|
||||
ctx.say(response).await?;
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
use once_cell::sync::OnceCell;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::{self};
|
||||
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct CoreConfig {
|
||||
/// Discord bot token.
|
||||
pub token: String,
|
||||
/// Folder to store program logs.
|
||||
pub log_dir: String,
|
||||
/// If user IDs should be hased in the database, disables @mentioning.
|
||||
pub hash_ids: bool,
|
||||
/// Channel where messages should be posted.
|
||||
pub channel: u64,
|
||||
/// List of user IDs of users who have admin perms with the bot.
|
||||
pub admins: Vec<i64>,
|
||||
}
|
||||
|
||||
impl Default for CoreConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
token: Default::default(),
|
||||
log_dir: "logs".to_string(),
|
||||
hash_ids: true,
|
||||
channel: 0,
|
||||
admins: vec![0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub static CORE_CFG: OnceCell<CoreConfig> = OnceCell::new();
|
||||
|
||||
pub fn load_core_cfg(file: &String) {
|
||||
let f_ = std::fs::File::open(format!("{}", file));
|
||||
|
||||
if f_.is_err() {
|
||||
CORE_CFG.set(CoreConfig::default()).expect("Could not set default values");
|
||||
println!("!! Using default config values becuase {} does not exist or could not be read !!", file);
|
||||
return;
|
||||
}
|
||||
|
||||
let r = CORE_CFG.set(serde_yaml::from_reader(f_.unwrap()).expect("Could not read values."));
|
||||
|
||||
if r.is_err() {
|
||||
CORE_CFG.set(CoreConfig::default()).expect("Could not set default values");
|
||||
println!("!! Using default config values becuase {} does not exist or could not be read !!", file)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
use once_cell::sync::OnceCell;
|
||||
use std::sync::atomic::*;
|
||||
use std::fs::{OpenOptions, File, create_dir_all};
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
pub enum LogLevel {
|
||||
Trace = 5,
|
||||
Debug = 10,
|
||||
Info = 20,
|
||||
Warn = 30,
|
||||
Error = 40,
|
||||
Critical = 50,
|
||||
Fatal = 100,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LogLevel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match *self {
|
||||
LogLevel::Trace => write!(f, "T"),
|
||||
LogLevel::Debug => write!(f, "D"),
|
||||
LogLevel::Info => write!(f, "I"),
|
||||
LogLevel::Warn => write!(f, "W"),
|
||||
LogLevel::Error => write!(f, "E"),
|
||||
LogLevel::Critical => write!(f, "C"),
|
||||
LogLevel::Fatal => write!(f, "F"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for LogLevel {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(input: &str) -> Result<LogLevel, Self::Err> {
|
||||
match input {
|
||||
"trace" => Ok(LogLevel::Trace),
|
||||
"debug" => Ok(LogLevel::Debug),
|
||||
"info" => Ok(LogLevel::Info),
|
||||
"warn" => Ok(LogLevel::Warn),
|
||||
"warning" => Ok(LogLevel::Warn),
|
||||
"error" => Ok(LogLevel::Error),
|
||||
"critical" => Ok(LogLevel::Critical),
|
||||
"fatal" => Ok(LogLevel::Fatal),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LEVEL: OnceCell<LogLevel> = OnceCell::new();
|
||||
static LOG_FILE: OnceCell<File> = OnceCell::new();
|
||||
static HAS_INITED: AtomicBool = AtomicBool::new(false);
|
||||
static FILE_IS_GOOD: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn init_logger(log_folder: &str, level: LogLevel) {
|
||||
if HAS_INITED.load(Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
LEVEL.set(level).unwrap();
|
||||
|
||||
HAS_INITED.store(true, Ordering::Relaxed);
|
||||
|
||||
let log_file = format!("{}/apollo.log", log_folder);
|
||||
let dir_create_result: Result<(), std::io::Error> = create_dir_all(log_folder);
|
||||
|
||||
if dir_create_result.is_err() {
|
||||
log(LogLevel::Error, "logging", "init", format!("Error creating log folder {}", log_folder).as_str());
|
||||
return;
|
||||
}
|
||||
|
||||
let f_ = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.create(true)
|
||||
.open(log_file);
|
||||
|
||||
|
||||
if f_.is_ok() {
|
||||
LOG_FILE.set(f_.unwrap()).unwrap();
|
||||
FILE_IS_GOOD.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
log(LogLevel::Error, "logging", "init", "Error getting logfile");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(level: LogLevel, module: &str, submodule: &str, message: &str) {
|
||||
if !HAS_INITED.load(Ordering::Relaxed) {
|
||||
println!("Logging before logger initialized!");
|
||||
return;
|
||||
}
|
||||
let timestamp: String = chrono::offset::Local::now().format("%F %X%.3f").to_string();
|
||||
let logstr: String = format!(
|
||||
"[{}]:{}:{}:{}:{}",
|
||||
timestamp, level, module, submodule, message
|
||||
);
|
||||
|
||||
if level >= *LEVEL.get().unwrap() {
|
||||
println!("{logstr}");
|
||||
|
||||
if FILE_IS_GOOD.load(Ordering::Relaxed) {
|
||||
let mut f = LOG_FILE.get().unwrap();
|
||||
let _ = writeln!(f, "{}", logstr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
use poise::serenity_prelude::{self as serenity};
|
||||
|
||||
mod config;
|
||||
use config::{load_core_cfg, CORE_CFG};
|
||||
|
||||
mod logging;
|
||||
use logging::{LogLevel, init_logger, log};
|
||||
|
||||
mod commands;
|
||||
use commands::{notify::*, Data};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
load_core_cfg(&"config.yaml".to_string());
|
||||
let cfg = CORE_CFG.get().unwrap();
|
||||
|
||||
init_logger(&cfg.log_dir, LogLevel::Info);
|
||||
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands: vec![notify()],
|
||||
..Default::default()
|
||||
})
|
||||
.token(&cfg.token)
|
||||
.intents(serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::DIRECT_MESSAGES | serenity::GatewayIntents::GUILD_MESSAGES)
|
||||
.setup(|ctx, _ready, framework| {
|
||||
Box::pin(async move {
|
||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||
Ok(Data {})
|
||||
})
|
||||
});
|
||||
|
||||
log(LogLevel::Info, "boot", "main", "WhisperWolf3 boot");
|
||||
framework.run().await.unwrap();
|
||||
}
|
Loading…
Reference in New Issue